410. 分割数组的最大值
给定一个非负整数数组 nums 和一个整数 m ,你需要将这个数组分成 m 个非空的连续子数组。
设计一个算法使得这 m 个子数组各自和的最大值最小。
示例 1:
输入:nums = [7,2,5,10,8], m = 2
输出:18
解释: 一共有四种方法将 nums 分割为 2 个子数组。
其中最好的方式是将其分为 [7,2,5] 和 [10,8] 。 因为此时这两个子数组各自的和的最大值为18,在所有情况中最小。
示例 2:
输入:nums = [1,2,3,4,5], m = 2
输出:9
示例 3:
输入:nums = [1,4,4], m = 3
输出:4
提示:
1 <= nums.length <= 1000
0 <= nums[i] <= 1e6
1 <= m <= min(50,nums.length)
解析:
- 将问题转化:在前边所有数字的基础上添加一个元素对结果产生的影响。例如:枚举到 7 2 5 8 10中的8时,转化为在7 2 5的基础上添加一个8会结果产生影响。
- 以8为结尾的子数组可能为8 ,8 5,8 5 2,8 5 2 7,如果m=3,可以怎么分配,这时就枚举8结尾的四个子数组作为第1组,让剩余数字产生剩下的2组。
- 8自身结合作为一组,那么就需要7 2 5产生两组。
- 8 5 作为一组,需要7 2 产生两组
- 8 5 2作为一组 ,7不可能产生两组所以枚举结束。
- 接下来加入10这个元素,m=3
以10结尾产生子数组为:10 ,10 8 ,10 8 5,10 8 5 2,10 8 5 2 7
-10作为一组,则7 2 5 8需要组成2组
-10 8作为一组,则7 2 5需要组成2组(子问题添加8的时候已经出现)
-10 8 5作为一组,则7 2组成2组(添加8的时候也出现了)
-10 8 5 2 作为一组,则7组成2组(不可能枚举结束)
我们用f[i][j]表示,以第 i 个数字为结尾时产生 j 组时,这 j 个子数组各自和的最大值最小为f[i][j].
code
class Solution {
public:
// 每个元素作为第m个子序列的最后一个元素的最大值最小值
int splitArray(vector<int>& nums, int m) {
int n=nums.size();
// f[0][i],f[i][0]不使用,防止越界,
//直接用f[i][j]表示以第i个元素结尾,分为j组时,各组最大的值最小的值
int f[n+1][m+1];
memset(f,0,sizeof(f));
// 只有一组情况
for(int i=1;i<n+1;i++){
f[i][1]=nums[i-1]+f[i-1][1];
}
// 枚举每个元素
for(int i=1;i<=n;i++){
// 枚举以当前元素结尾产生的组数
for(int j=2;j<=m;j++){
// 以当前i元素结尾,产生j组时各组最大值最小
int tmp=0,tmp2=INT_MAX;
// 元素i结尾最多可以结合i个元素
for(int k=i;k>0;k-- ){
tmp+=nums[k-1];
// 如果需要的组数>剩余数字数
if(j-1>k-1) break;
// 前k-1个元素,产生j-1组的最大元素,
//与最后一组的最大值
int a=max(tmp,f[k-1][j-1]);
// 枚举所有与第i个元素结合情况,取最小值
tmp2=min(tmp2,a);
}
f[i][j]=tmp2;
}
}
return f[n][m];
}
};