AI刷题之非重叠子数组的最大和 | 豆包MarsCode AI刷题

123 阅读3分钟

问题描述

小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

本题考察:此题考察了动态规划、数组的操作等。

解题思路:我们需要先找到数组中两个非重叠的子数组,它们的长度分别为 firstLensecondLe,并且它们的和最大。这两个子数组可以相互独立,顺序没有限制,但不能有任何重叠。我们可以计算前缀和数组,定义max函数,确保在遍历的时候取最大值

首先,定义一个变量firstLen存储前缀和,优化求解过程。这段代码计算数组nums的前缀和数组prefixSum,让prefixSum[i]表示数组中nums中前i个元素的和。为了快速计算任意子数组的和,我们可以预先计算出一个前缀和数组 prefixSumprefixSum[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];
}

然后定义两个变量maxlen1result分别用来表示当前长度的子数组的最大和,另一个用于表示两个子数组的最大和。通过动态规划的思想,通过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); 
    }
}