问题描述
小R遇到一个数组 nums,他需要从中找到两个非重叠的子数组,它们的长度分别为 firstLen 和 secondLen。这两个子数组可以相互独立,顺序没有限制,但它们不能有任何重叠。你需要帮小R找出这些子数组的最大和。
测试样例
样例1:
输入:
nums = [0,6,5,2,2,5,1,9,4], firstLen = 1, secondLen = 2
输出:20
样例2:
输入:
nums = [3,8,1,3,5,2,1,0], firstLen = 3, secondLen = 2
输出:21
样例3:
输入:
nums = [2,1,4,3,5,9,5,0,3,8], firstLen = 4, secondLen = 3
输出:33
本题考察:此题考察了动态规划、数组的操作等。
解题思路:我们需要先找到数组中两个非重叠的子数组,它们的长度分别为 firstLen 和 secondLe,并且它们的和最大。这两个子数组可以相互独立,顺序没有限制,但不能有任何重叠。我们可以计算前缀和数组,定义max函数,确保在遍历的时候取最大值
首先,定义一个变量firstLen存储前缀和,优化求解过程。这段代码计算数组nums的前缀和数组prefixSum,让prefixSum[i]表示数组中nums中前i个元素的和。为了快速计算任意子数组的和,我们可以预先计算出一个前缀和数组 prefixSum,prefixSum[i] 表示数组 nums 中从开头到位置 i-1 的累积和。这样可以在 O(1) 的时间内计算任意子数组的和。
int n = nums.length;
int[] prefixSum = new int[n + 1]; // 前缀和数组,长度为 n+1
for (int i = 1; i <= n; i++) {
prefixSum[i] = prefixSum[i - 1] + nums[i - 1];
}
然后定义两个变量maxlen1和result分别用来表示当前长度的子数组的最大和,另一个用于表示两个子数组的最大和。通过动态规划的思想,通过for循环遍历数组nums,更新maxLen1和result,找到满足条件的两个非重叠子数组的最大和
int maxLen1 = 0;
int result = 0;
// 遍历数组,确保 len1 的子数组在 len2 的前面
for (int i = len1 + len2; i <= n; i++) {
maxLen1 = Math.max(maxLen1, prefixSum[i - len2] - prefixSum[i - len2 - len1]);
result = Math.max(result, maxLen1 + prefixSum[i] - prefixSum[i - len2]);
}
既然 firstLen 和 secondLen 的顺序可以互换,我们需要在 main 函数中调用 maxSum 两次,一次是 firstLen 在 secondLen 前,另一次是 secondLen 在 firstLen 前,并取其最大值。
public static int solution(int[] nums, int firstLen, int secondLen) {
return Math.max(maxSum(nums, firstLen, secondLen), maxSum(nums, secondLen, firstLen));
}
最后使用maxSum函数计算两个非重叠子数组的最大和。通过前缀和数组来加速子数组和的九三,利用maxLen1和result来动态更新满足条件的最大和。
private static int maxSum(int[] nums, int len1, int len2) {
int n = nums.length;
int[] prefixSum = new int[n + 1];
for (int i = 1; i <= n; i++) {
prefixSum[i] = prefixSum[i - 1] + nums[i - 1];
}
int maxLen1 = 0;
int result = 0;
for (int i = len1 + len2; i <= n; i++) {
maxLen1 = Math.max(maxLen1, prefixSum[i - len2] - prefixSum[i - len2 - len1]);
result = Math.max(result, maxLen1 + prefixSum[i] - prefixSum[i - len2]);
}
return result;
}
这道题目不算太难,附上本题目的答案:
public class Main {
public static int solution(int[] nums, int firstLen, int secondLen) {
return Math.max(maxSum(nums, firstLen, secondLen), maxSum(nums, secondLen, firstLen));
}
private static int maxSum(int[] nums, int len1, int len2) {
int n = nums.length;
int[] prefixSum = new int[n + 1];
for (int i = 1; i <= n; i++) {
prefixSum[i] = prefixSum[i - 1] + nums[i - 1];
}
int maxLen1 = 0, result = 0;
for (int i = len1 + len2; i <= n; i++) {
maxLen1 = Math.max(maxLen1, prefixSum[i - len2] - prefixSum[i - len2 - len1]);
result = Math.max(result, maxLen1 + prefixSum[i] - prefixSum[i - len2]);
}
return result;
}
public static void main(String[] args) {
System.out.println(solution(new int[]{0, 6, 5, 2, 2, 5, 1, 9, 4}, 1, 2) == 20);
System.out.println(solution(new int[]{3, 8, 1, 3, 5, 2, 1, 0}, 3, 2) == 21);出:
System.out.println(solution(new int[]{2, 1, 4, 3, 5, 9, 5, 0, 3, 8}, 4, 3) == 33);
}
}