Split Array Largest Sum LT410

时间:2023-09-03 08:35:32

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.

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.

Note:
If n is the length of array, assume the following constraints are satisfied:

  • 1 ≤ n ≤ 1000
  • 1 ≤ m ≤ min(50, n)

Idea 1. dynmaic programming, similar to Capacity To Ship Packages Within D Days LT1011

dp(i)(m) = min(i <= k <= n - m) max(prefixSum(k+1) - prefixSum(i), dp(k+1)(m-1))

Note: prefixSum integer overflow, pls use long.

Time complexity: O(mn^2)

Space complexity: O(n)

 class Solution {
public int splitArray(int[] nums, int m) {
int n = nums.length; long[] prefixSum = new long[n+1];
for(int i = 1; i <= n; ++i) {
prefixSum[i] = prefixSum[i-1] + nums[i-1];
} long[] dp = new long[n];
for(int i = 0; i < n; ++i) {
dp[i] = prefixSum[n] - prefixSum[i];
} for(int split = 2; split <= m; ++split) {
for(int i = 0; i <= n -split; ++i) {
for(int k = i; k <= n - split; ++k) {
long val = Math.max(prefixSum[k+1] - prefixSum[i], dp[k+1]);
dp[i] = Math.min(dp[i], val);
// if(val <= dp[i]) { //positive optimisation
// dp[i] = val;
// }
// else {
// break;
// }
}
}
} return (int)dp[0];
}
}

Idea 2. binary search

search space: min = max(max(nums), sum(nums)/m), max = sum(nums)

 class Solution {
private int checkSplits(int[] nums, int load) {
int splits = 1;
int sum = 0;
for(int num: nums) {
if(sum + num > load) {
++splits;
sum = num;
}
else sum += num;
}
return splits;
}
public int splitArray(int[] nums, int m) {
int n = nums.length; long sum = 0;
int minSum = 0;
for(int num: nums) {
minSum = Math.max(minSum, num);
sum += num;
} int maxSum = (int)(sum);
minSum = Math.max(minSum, (int)(sum-1)/m + 1);
while(minSum < maxSum) {
int mid = minSum + (maxSum - minSum)/2;
int splits = checkSplits(nums, mid);
if(splits <= m) {
maxSum = mid;
}
else {
minSum = mid + 1;
}
}
return minSum;
}
}