题目描述
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.
思路
思路一:动态规划。对前 i 个数字,遍历从第k组的划分点 j。时间复杂度:O(knn)
思路二:二分。每组和的最大值的最小值,边界分别是划分为1组或者n组时,即数组中数字最大值和数组和。二分查找,当给定最大和为C时,计算可以划分多少组。 时间复杂度:O(log(sum(nums))*n)
代码
动态规划:
class Solution {
public:
int splitArray(vector<int>& nums, int m) {
int n = nums.size();
vector<long long> sum(n);
vector<vector<long long>> dp(n+1, vector<long long>(n+1, INT_MAX));
sum[0] = nums[0];
for (int i=1; i<n; ++i) {
sum[i] = nums[i] + sum[i-1];
}
for (int k=1; k<=m; ++k) {
for (int i=0; i<n; ++i) {
dp[i][1] = sum[i];
if (k == 1) continue;
for (int j=1; j<=i; ++j) {
dp[i][k] = min(dp[i][k], max(dp[j-1][k-1], (sum[i] - sum[j-1])));
}
}
}
return dp[n-1][m];
}
};
二分:
class Solution {
public:
int splitArray(vector<int>& nums, int m) {
long long l = *max_element(nums.begin(), nums.end());
long long r = 0;
int n = nums.size();
for (int i=0; i<n; ++i) r += nums[i];
while(l <= r) {
long long mid = l + (r - l) / 2;
long long tsum = 0;
int k = 0;
for (int i=0; i<n; ++i) {
tsum += nums[i];
if (tsum > mid) {
tsum = 0;
k++;
i--;
}
}
if (tsum) k++;
if (k > m) {
l = mid + 1;
}else {
r = mid - 1;
}
}
return l;
}
};