LWC 52:689. Maximum Sum of 3 Non-Overlapping Subarrays

LWC 52:689. Maximum Sum of 3 Non-Overlapping Subarrays

传送门:689. Maximum Sum of 3 Non-Overlapping Subarrays

Problem:

In a given array nums of positive integers, find three non-overlapping subarrays with maximum sum.

Each subarray will be of size k, and we want to maximize the sum of all 3*k entries.

Return the result as a list of indices representing the starting position of each interval (0-indexed). If there are multiple answers, return the lexicographically smallest one.

Example:

Input: [1,2,1,2,6,7,5,1], 2
Output: [0, 3, 5]
Explanation: Subarrays [1, 2], [2, 6], [7, 5] correspond to the starting indices [0, 3, 5].
We could have also taken [2, 1], but an answer of [1, 3, 5] would be lexicographically larger.

Note:

  • nums.length will be between 1 and 20000.
  • nums[i] will be between 1 and 65535.
  • k will be between 1 and floor(nums.length / 3).

思路:
dp[i]:表示从i下标开始,长度为k的subArray的和。dp[i] = nums[i] + nums[i+1]+...+nums[i+k-1],这样给定当前坐标i,只需要求出位于左侧的最大max{dp[i'] | i' <= i - k}记录之,同理求出右侧的最大max{dp[j] | j >= i + k}

代码如下:

    public int[] maxSumOfThreeSubarrays(int[] nums, int k) {
        int n = nums.length;
        int[] sum = new int[n + 1];
        // 累加和,区间计算时,只需O(1)
        for (int i = 0; i < n; ++i) {
            sum[i + 1] = nums[i] + sum[i]; 
        }

        int[] dp = new int[n];

        // 对应最后一个区间的选择范围
        for (int l = 2 * k; l + k <= n; ++l) {
            dp[l] = sum[l + k] - sum[l];
        }

        // 对应第二个区间的选择范围
        for (int l = k; l + 2 * k <= n; ++l) {
            dp[l] = sum[l + k] - sum[l];
        }

        // 对应第一个区间的选择范围
        for (int l = 0; l + 3 * k <= n; ++l) {
            dp[l] = sum[l + k] - sum[l];
        }

        // 记录当前i下,符合i' <= i - k的dp[i']中最大下标
        int[] left = new int[n];
        for (int i = 0; i < n; ++i) {
            if (i - k >= 0) {
                if (left[i - 1] == -1) {
                    left[i] = i - k;
                }
                else if (dp[i - k] <= dp[left[i - 1]]) {
                    left[i] = left[i - 1];
                }
                else{
                    left[i] = i - k;
                }
            }
            else {
                left[i] = -1; //表示当前i的左侧没有合法的i'
            }
        }

        // 记录当前i下,符合j >= i + k的dp[j]中最大下标
        int[] right = new int[n];
        for (int i = n - 1; i >= 0; --i) {
            if (i + k < n) {
                if (right[i + 1] == -1) {
                    right[i] = i + k;
                }
                else if (dp[right[i + 1]] > dp[i + k]) {
                    right[i] = right[i + 1];
                }
                else {
                    right[i] = i + k;
                }
            }
            else {
                right[i] = -1; //表示当前i的右侧没有合法的j
            }
        }

        int max = 0;
        int[] res = {-1, -1, -1};
        for (int i = 0; i < n; ++i) {
            if (left[i] != -1 && right[i] != -1) {
                int tmp = dp[i] + dp[right[i]] + dp[left[i]];
                if (tmp > max) {
                    max = dp[i] + dp[right[i]] + dp[left[i]];
                    res[0] = left[i];
                    res[1] = i;
                    res[2] = right[i];
                }
            }
        }
        return res;
    }

注意求解left和right中选取最大值的if判断,一个有等号,一个无等号,是为了 return the lexicographically smallest one.

精简版本:

    public int[] maxSumOfThreeSubarrays(int[] nums, int k) {
        int n = nums.length;
        int[] sum = new int[n + 1];
        for (int i = 0; i < n; ++i) {
            sum[i + 1] = nums[i] + sum[i]; 
        }

        int[] dp = new int[n];

        for (int i = 0; i + k <= n; ++i){
            dp[i] = sum[i + k] - sum[i];
        }

        int[] left = new int[n];
        Arrays.fill(left, -1);
        for (int i = k; i < n; ++i) {
            if (i - k == 0 || dp[i - k] > dp[left[i - 1]]) {
                left[i] = i - k;
            }
            else {
                left[i] = left[i - 1];
            }
        }

        int[] right = new int[n];
        Arrays.fill(right, -1);
        for (int i = n - k - 1; i >= 0; --i) {
            if (i + k == n - 1 || dp[right[i + 1]] <= dp[i + k]){
                right[i] = i + k;    
            }
            else{
                right[i] = right[i + 1];
            }
        }

        int max = 0;
        int[] res = {-1, -1, -1};
        for (int i = 0; i < n; ++i) {
            if (left[i] != -1 && right[i] != -1) {
                int tmp = dp[i] + dp[right[i]] + dp[left[i]];
                if (tmp > max) {
                    max = dp[i] + dp[right[i]] + dp[left[i]];
                    res[0] = left[i];
                    res[1] = i;
                    res[2] = right[i];
                }
            }
        }
        return res;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值