Given an array of integers, find two non-overlapping subarrays which have the largest sum.
The number in each subarray should be contiguous.
Return the largest sum.
The subarray should contain at least one number
Example
For given[1, 3, -1, 2, -1, 2], the two subarrays are[1, 3]and[2, -1, 2]or[1, 3, -1, 2]and[2], they both have the largest sum7.
Challenge
Can you do it in time complexity O(n) ?
Analysis
Maximum Subarray II 与 Maximum Subarray I 相比,有几处难点:
用 local 变量更新然后返回 global 最优还不够,需要保存对于每一个子问题的 global 最优(可能并不以当前位置结尾),用于后面的左右两边全局查询
相比 Prefix Sum,个人更偏好Kadane's Algorithm,但是用 Kadane's Algorithm 要注意初始化问题(从头到尾循环,必须要以 nums[0] 做初始化,从 index = 1 开始搜;或者从尾到头循环则以nums[n-1]初始化,从index = n - 2开始)。
Solution
Kadane's Algorithm - O(n) space, O(n) time
publicclassSolution {/* * @param nums: A list of integers * @return: An integer denotes the sum of max two non-overlapping subarrays */publicintmaxTwoSubArrays(List<Integer> nums) {if (nums ==null||nums.size() ==0) return0;int n =nums.size();// left[] stores the global max subarray sum for [0, ..., i] int[] left =newint[n];// right[] stores the global max subarray sum for [i, ..., n - 1] int[] right =newint[n];// Initialize left[] array left[0] =nums.get(0);int prevMax = left[0];int max = left[0];// Loop from left to rightfor (int i =1; i < n; i++) { prevMax =Math.max(prevMax +nums.get(i),nums.get(i)); max =Math.max(max, prevMax); left[i] = max; }// Initialize right[] array right[n -1] =nums.get(n -1); prevMax = right[n -1]; max = right[n -1];// Loop from right to leftfor (int i = n -2; i >=0; i--) { prevMax =Math.max(prevMax +nums.get(i),nums.get(i)); max =Math.max(max, prevMax); right[i] = max; }// Find max sum of left and right subarraysint result =Integer.MIN_VALUE;for (int i =0; i < n -1; i++) { result =Math.max(result, left[i] + right[i +1]); }return result; }}
Prefix Sum Approach - O(n) space, O(n) time
publicclassSolution { /** * @param nums: A list of integers * @return: An integer denotes the sum of max two non-overlapping subarrays */publicintmaxTwoSubArrays(ArrayList<Integer> nums) {// write your codeif(nums ==null||nums.size() ==0) return0;int n =nums.size();// Maximum subarray value from left/right with n elementsint[] left =newint[n];int[] right =newint[n];int prefixSum =0;int minSum =0;int max =Integer.MIN_VALUE;for(int i =0; i < n; i++){ prefixSum +=nums.get(i); max =Math.max(max, prefixSum - minSum); minSum =Math.min(minSum, prefixSum); left[i] = max; } prefixSum =0; minSum =0; max =Integer.MIN_VALUE;for(int i = n -1; i >=0; i--){ prefixSum +=nums.get(i); max =Math.max(max, prefixSum - minSum); minSum =Math.min(minSum, prefixSum); right[i] = max; }int rst =Integer.MIN_VALUE;for(int i =0; i < n -1; i++){ rst =Math.max(rst, left[i] + right[i +1]); }return rst; }}