Question:
Given an array of integers and a number k, find k non-overlapping
subarrays which have the largest sum.
The number in each subarray should be contiguous.
Return the largest sum.
Example:
Given [-1,4,-2,3,-2,3]
, k=2
, return 8
Analysis:
这题属于动态规划里比较难的一题。首先定义状态,f[i][j]表示:在前i个元素中取出j个不重叠的子数组的和的最大值(也就是要将前i个元素组成的数组划分成j个部分,每个部分求最大子数组,然后相加)。状态定义好了之后,需要找到状态之间的关联,也就是求动态转移方程。可以将f[i][j]拆分成两部分来看,第一部分是f[x][j - 1],x为j - 1~ i - 1之间的任意值,表示前x个元素中取j - 1个子数组的和的最大值。第二部分是[x, x + 1, ..., i - 1]数组,求这个数组的maximum subarray(可以理解为在数组[0, 1, ..., x - 1, x, ..., i - 1]中任意切一刀,分成两部分。index为x - 1的地方就是那一刀切的地方,第一部分是[0, 1, ..., x - 1],第二部分是[x, x + 1, ..., i - 1])。由此得到动态转移方程为:f[i][j] = f[x][j - 1] + maxSubarray([x, x + 1, ..., i - 1])。求max subarray的方法可以参考maximum subarray那道题。
Code:
1 public class Solution { 2 /** 3 * @param nums: A list of integers 4 * @param k: An integer denote to find k non-overlapping subarrays 5 * @return: An integer denote the sum of max k non-overlapping subarrays 6 */ 7 public int maxSubArray(int[] nums, int k) { 8 int length = nums.length; 9 if(length < k) { 10 return 0; 11 } 12 13 //f[i][j] means max sum of j subarrays from nums[0] to nums[i - 1], i from 0 ~ length, 14 //j from 0 ~ k 15 int[][] f = new int[length + 1][k + 1]; 16 for(int i = 0; i <= length; i++) { 17 f[i][0] = 0; 18 } 19 for(int j = 0; j <= k; j++) { 20 f[0][j] = 0; 21 } 22 23 //i depends on j, so first start loop of j 24 for(int j = 1; j <= k; j++) { 25 for(int i = j; i <= length; i++) { 26 f[i][j] = Integer.MIN_VALUE; 27 int sum = 0, max = Integer.MIN_VALUE, minSum = 0; 28 for(int x = i - 1; x >= j - 1; x--) { 29 sum += nums[x]; 30 max = Math.max(max, sum - minSum); 31 minSum = Math.min(minSum, sum); 32 33 f[i][j] = Math.max(f[i][j], f[x][j - 1] + max); 34 } 35 } 36 } 37 38 return f[length][k]; 39 } 40 }
Complexity:
时间复杂度是O(k * n^2), n是nums数组的长度,k是题目要求的subarrays的个数。空间复杂度就是新开的f二维数组,O(n * k)。
参考:
https://wxx5433.gitbooks.io/interview-preparation/content/part_ii_leetcode_lintcode/dp/maximum_subarray_iii.html