https://leetcode-cn.com/problems/split-array-largest-sum/
有两种思路。一种是dp。对于 [0,j] 之间的元素要分成 i 组。则可以对于所有 0<=k<j,都可以将[0,k]分成 i-1 组。[k,j]分生一组。看两部分最大值哪个大。取大的即可。复杂度是O(mn^2)
class Solution {
public:
int splitArray(vector<int>& nums, int m) {
int n = nums.size();
vector<long long> presum(n + 1, 0);
for(int i = 1; i <= n; i++) presum[i] = presum[i - 1] + nums[i - 1];
long long dp[m + 1][n + 1];
memset(dp, 0x3f, sizeof dp);
for(int j = 1; j <= n; j++) dp[1][j] = presum[j]; // 分成一组
for(int i = 2; i <= m; i++) // i组
for(int j = i; j <= n; j++) // 元素个数j要大于等于i组
for(int k = 0; k < j; k++)
dp[i][j] = min(dp[i][j], max(dp[i - 1][k], presum[j] - presum[k]));
return dp[m][n];
}
};
还有就是二分加判定的思路。对于一个区间和mid。要将数组分成多个组。每个组里的元素之和都要小于等于mid。假设能分成k组。如果k大于m。就说明mid太小,可以尝试更大,令l=mid+1。否则r=mid。复杂度是O(nlong(sum(nums))).
class Solution {
public:
int splitArray(vector<int>& nums, int m) {
long long l = *max_element(nums.begin(), nums.end());
long long r = accumulate(nums.begin(), nums.end(), 0LL);
while(l < r)
{
long long mid = l + r >> 1;
//cout << mid << " " << check(mid, nums, m) << endl;
if(check(mid, nums, m))
l = mid + 1;
else
r = mid;
}
return l;
}
bool check(long long mid, vector<int>& nums, int m)
{
long long sum = 0, cnt = 1;
for(int i : nums)
{
if(sum + i > mid)
{
sum = i;
cnt++;
}
else
{
sum += i;
}
}
//cout << mid << " " << cnt << endl;
if(cnt > m) return true;
return false;
}
};