Given an array which consists of non-negative integers and an integer m, you can split the array into m non-empty continuous subarrays. Write an algorithm to minimize the largest sum among these m subarrays.
Note:
If n is the length of array, assume the following constraints are satisfied:
- 1 ≤ n ≤ 1000
- 1 ≤ m ≤ min(50, n)
Examples:
Input:
nums = [7,2,5,10,8]
m = 2
Output:
18
Explanation:
There are four ways to split nums into two subarrays.
The best way is to split it into [7,2,5] and [10,8],
where the largest sum among the two subarrays is only 18.
思路:二分答案:如果细分空间越小,趋近于n, 最低的sum就是max(A[i]) ,如果只有一个区间,那么就是sum[0~n-1];
注意最后判断的时候,先判断start,然后判断end;还有sum有可能爆,改成long就可以了。Time: log(sum(Ai))*n Space: O(N)
class Solution {
public int splitArray(int[] nums, int m) {
if(nums == null || nums.length == 0) {
return 0;
}
int max = nums[0];
long sum = 0;
for(int num: nums) {
max = Math.max(max, num);
sum += num;
}
long start = max; long end = sum;
while(start + 1 < end){
long mid = start + (end - start) / 2;
if(cansplit(nums, mid) > m) {
start = mid;
} else {
end = mid;
}
}
// 首先check start,然后check end;
if(cansplit(nums, start) > m) {
return (int)end;
}
return (int)start;
}
private int cansplit(int[] nums, long limit) {
int j = 0;
long cursum = 0;
int count = 0;
while(j < nums.length) {
while(j < nums.length && cursum + nums[j] <= limit) {
cursum += nums[j];
j++;
}
cursum = 0;
count++;
}
return count;
}
}
思路2:这题可以用dp,DFS +memo cache
前面一段leftsum可以用prefixsum求出,后面是一个子问题 切成m - 1段;
Time: O(m*n^2) Space: O(m*n); Dp可以扩展成有负数的情况,如果全部是正数,还是上面的binary search占优势;
class Solution {
public int splitArray(int[] nums, int m) {
if(nums == null || nums.length == 0) {
return 0;
}
int n = nums.length;
int[] prefixsum = new int[n+1];
prefixsum[0] = 0;
for(int i = 1; i <= n; i++) {
prefixsum[i] = prefixsum[i - 1] + nums[i - 1];
}
int[][] cache = new int[n][m+1];
return splitArrayHelper(0, m, cache, nums, prefixsum);
}
private int splitArrayHelper(int j, int m, int[][] cache, int[] nums,
int[] prefixsum) {
int n = nums.length;
if(m == 1) {
return prefixsum[n] - prefixsum[j];
}
if(cache[j][m] != 0) {
return cache[j][m];
}
int res = Integer.MAX_VALUE;
for(int k = j; k < n - 1; k++) {
// j ~k sum;
int leftsum = prefixsum[k+1] - prefixsum[j];
// k+1 ~ n sum;
int rightsum = splitArrayHelper(k+1, m - 1, cache, nums, prefixsum);
res = Math.min(res, Math.max(leftsum, rightsum));
}
cache[j][m] = res;
return res;
}
}