链接
https://leetcode-cn.com/problems/split-array-largest-sum/
耗时
解题:null min
题解:18 min
题意
给定一个非负整数数组和一个整数 m,你需要将这个数组分成 m 个非空的连续子数组。设计一个算法使得这 m 个子数组各自和的最大值最小。
思路
没有思路,下面是看完题解思路后,我重新想了一遍的复述。
dp[i][j] 表示数组前 i 个整数分成 j 个非空的连续子数组各自和的最大值最小为 dp[i][j]。那么分为两种情况,i < j,此时不合法,赋值为 INF;i >= j,这是合法的,dp[i][j] 可以由 dp[k][j-1] 获得,即前 k 个整数分成 j-1 个非空的连续子数组,k+1 到 i 作为第 j 个非空的连续子数组,所以 dp[k][j-1] 和 sum(num[k+1], ···, num[i])中的较大者即是当前情况的最大值。那么 dp[i][j] = 所有可能情况的最大值 中的最小者 min{max(dp[k][j-1], sum(k+1,i)) | (j-1<=k<=i-1)}。
状态转移方程:
d
p
[
i
]
[
j
]
=
min
k
=
j
−
1
i
−
1
(
max
(
d
p
[
k
]
[
j
−
1
]
,
∑
n
u
m
[
k
+
1
:
i
]
)
)
dp[i][j] = \min_{k=j-1}^{i-1}(\max(dp[k][j-1], \sum num[k+1 : i]))
dp[i][j]=k=j−1mini−1(max(dp[k][j−1],∑num[k+1:i]))
细节:初始化时将 dp 全部赋值为 INF,dp[0][0] = 0 因为 dp[1][1] 从它转移来。
时间复杂度: O ( n 2 ∗ m ) O(n^2*m) O(n2∗m)
AC代码
class Solution {
public:
typedef long long LL;
int splitArray(vector<int>& nums, int m) {
int n = nums.size();
vector<vector<LL>> dp(n+1, vector<LL>(m+1, LLONG_MAX));
// sum
vector<LL> sum(n+1, 0);
for(int i = 0; i < n; ++i) sum[i+1] = sum[i]+nums[i];
// dp
dp[0][0] = 0;
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= min(i,m); ++j) {
for(int k = j-1; k <= i-1; ++k) {
dp[i][j] = min(dp[i][j], max(dp[k][j-1], sum[i]-sum[k]));
}
}
}
return dp[n][m];
}
};