LeetCode689. Maximum Sum of 3 Non-Overlapping Subarrays

53 篇文章 0 订阅
31 篇文章 0 订阅

Solution1: Divide and Conquer

This question asks for the three non-overlapping intervals with maximum sum. So this can be divided into 3 parts – find 3 non-overlapping intervals respectively, and combining the results to get the 3 non-overlapping intervals we want. Since each interval is of length k, suppose the start index of the middle interval is i, then the range of i’s value is: k <=i <= n-2k. Actually this i has also indicated the limits of the range of the first interval and the range of the last interval. Hence we have the following DP components:

left[i] stores the start index for the first interval in range [0, i]
right[i] stores the start index for the third interval in range [i, n - 1]

After that we can test every possible start index of middle interval, i.e. k <= i <= n - 2k. And based on the above 2 DP results, we can easily get the first and third max sum intervals. The runtime of this process is O(n).

Note that this question asks for the lexicographical smallest order interval, that is, when there are two intervals with the same max sum, we always select the leftmost one. So in this solution, for the first interval, since we are iterating from left to right, the comparison if statement use currSum > total. And for the third interval, we are iterating from right to left, the comparison if statement use currSum >= total.

Another trick we use here, to ensure the algorithm runs in O(n) time, is that we use predix sum to get the sum of a consecutive subarray in O(1) time. Otherwise, if we calaulate the interval sum each time, that would be O(k) time for each interval.

Run time complexity of this algorithm is O(n). Space complexity is O(n). n is the length of the input nums array.

class Solution {
    public int[] maxSumOfThreeSubarrays(int[] nums, int k) {
        int n = nums.length;
        int[] sum = new int[n + 1];
        int[] left = new int[n];
        int[] right = new int[n];
        int[] ret = new int[3];

        // First get the prefix sum of nums.
        // Prefix sum enables us to get the sum of k consecutive element in O(1) time
        for (int i = 0; i < n; i++) {
            sum[i + 1] = sum[i] + nums[i];
        }

        // DP for the left intetval max sum
        for (int i = k, tot = sum[k] - sum[0]; i < n; i++) {
            if (sum[i + 1] - sum[i - k + 1] > tot) {
                tot = sum[i + 1] - sum[i - k + 1];
                left[i] = i - k + 1;
            } else {
                left[i] = left[i - 1];
            }
        }

        // DP for the right interval max sum
        right[n - k] = n - k;
        for (int i = n - 1 - k, tot = sum[n] - sum[n - k]; i >= 0; i--) {
            if (sum[i + k] - sum[i] >= tot) {
                tot = sum[i + k] - sum[i];
                right[i] = i;
            } else {
                right[i] = right[i + 1];
            }
        }

        // Find the max sum by iterating through the middle interval index based on above 2 cache.
        int maxSum = 0;
        for (int i = k; i <= n - 2 * k; i++) {
            int l = left[i - 1], r = right[i + k];
            int tot = sum[l + k] - sum[l] + sum[r + k] - sum[r] + sum[i + k] - sum[i];
            if (tot > maxSum) {
                ret[0] = l;
                ret[1] = i;
                ret[2] = r;
                maxSum = tot;
            }
        }

        return ret;
    }
}

Solution2: Generalized method

This is a generalized method for 689. Maximum Sum of 3 Non-Overlapping Subarrays
.

In this solution, dp[i][j] is used for recording for ith interval, what are the max sums for first j numbers in each position. And index[i][j] is used for recording for ith interval, what are the current start index for first j numbers that made up the max sum.

Thus after the searching ends, dp[n][nums.length] stores the max sum we can get and index[n][nums.length] stores the start index of last interval for the max sum. And now we can search backwards for each previous start index based on the start index of current interval. Because the start index of previous interval is the index stored in index[i - 1][current start index], which is the max sum of the subarray before current start index.

Run time complexity is O(n * len) where n is the number of intervals needed and len is the length of input array.

Space complexity is O(n * len) as well.

class MaxSumOfThreeSubarrays {
    /**
     * 
     * @param nums input array of numbers
     * @param k length of each interval
     * @param n number of intervals 
     * @return start index of each interval that has the maximum sum
     */
    public int[] maxSumOfThreeSubarrays(int[] nums, int k, int n) {
        int[][] dp = new int[n + 1][nums.length + 1];
        int[][] index = new int[n + 1][nums.length + 1];
        int tot = 0;
        // prefix sum
        int[] sum = new int[nums.length + 1];
        for (int i = 0; i < nums.length; i++) {
            sum[i + 1] = nums[i] + sum[i];
        }

        for (int i = 1; i <= n; i++) {
            for (int j = k - 1; j < nums.length; j++) {
                int tmpMax = sum[j + 1] - sum[j - k + 1] + dp[i - 1][j - k + 1];
                if (tmpMax > dp[i][j]) {
                    dp[i][j + 1] = tmpMax;
                    index[i][j + 1] = j - k + 1;
                } else {
                    dp[i][j + 1] = dp[i][j];
                    index[i][j + 1] = index[i][j];
                }
            }
        }

        int[] ret = new int[n];
        int prev = nums.length;
        for (int i = n; i > 0; i--) {
            ret[i - 1] = index[i][prev];
            prev = ret[i - 1];
        }

        return ret;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

耀凯考前突击大师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值