-
一种复杂度过高的方案
d p [ l ] [ r ] [ m ] = m i n l = < k < r ( m a x ( d p [ l ] [ k ] [ m 1 ] , d p [ k + 1 ] [ r ] [ m 2 ] ) ( m 1 + m 2 = = m ) ) dp[l][r][m]=min_{l=<k<r}(max(dp[l][k][m1],dp[k+1][r][m2]) \ \ (m1+m2==m)) dp[l][r][m]=minl=<k<r(max(dp[l][k][m1],dp[k+1][r][m2]) (m1+m2==m)) -
正解:
- 状态: d p [ i ] dp[i] dp[i] 表示区间 [ 0 , i ] [0,i] [0,i] 分成m个区间的dp值;
- d p [ i ] [ m ] = m i n ( d p [ i ] [ m ] , m a x ( d p [ j − 1 ] [ m − 1 ] , s [ i ] − s [ j − 1 ] ) dp[i][m] = min(dp[i][m], max(dp[j-1][m-1],s[i]-s[j-1]) dp[i][m]=min(dp[i][m],max(dp[j−1][m−1],s[i]−s[j−1]) (s[i]是前缀和)
-
空间的优化:由于dp[i][m]只依赖于dp[j][m-1],可以用滚动的数组进行优化,也就是完全可以省去第二个维度。但是,要注意倒过来更新。
空间复杂度: O ( n ) O(n) O(n) -
利用单调性去优化
(注,这种做法和887鸡蛋掉落 如出一辙。 )- 二分
注意到,在 i , m i,m i,m都固定的时候, d p [ j − 1 ] , s [ i ] − s [ j − 1 ] dp[j-1],s[i]-s[j-1] dp[j−1],s[i]−s[j−1]一个是关于 j j j单调递增的函数,
一个是关于 j j j单调递减的函数,所以那个我们要求的 j j j其实就是两个函数的交点极其临近点(因为不是连续的函数)。这可以用二分求出。
时间复杂度: O ( m ∗ n ∗ l o g ( n ) ) O(m*n*log(n)) O(m∗n∗log(n))
- 二分
/*
区间[0,i] 分成m个区间的dp值,
dp[i][m] = min(dp[i][m], max(dp[j-1][m-1],s[i]-s[j-1]);
*/
class Solution {
public:
int splitArray(vector<int>& a, int M) {
int n = a.size(), s[1010] = {
0} , dp[1010] = {
0};
s[0] = a[0];
for(int i=1;i<n;i++) s[i] = s[i-1]+a[i];
for(int i=0;i<n;i++) dp[i] = s[i];
for(int m=2;m<=M;m++){
for(int i=n-1;i>=1;i--){
// 暴力枚举 j
// int res = 1e9;
// for(int j=1;j<=i;j++){
// res = min(res,max(dp[j-1],s[i]-s[j-1]));
// }
// dp[i] = res;
// 二分卡出 j
int l = 1,r = i;
while(l<r){
int mid = l+(r-l+1)/2;
if(dp[mid-1]>=s[i]-s[mid-1]){
r = mid-1;
}else{
l = mid;
}
}
dp[i] = min(max(dp[l-1],s[i]-s[l-1]) ,max(dp[l],s[i]-s[l]));
}
}
return dp[n-1];
}
};
- 利用决策单调性优化
时间复杂度: O ( n ∗ m ) O(n*m) O(n∗m)
空间复杂度: O ( n ) O(n) O(n)
class Solution {
public:
int splitArray(vector<int>& a, int M) {
int n = a.size(), s[1010] = {
0} , dp[1010] = {
0};
s[0] = a[0];
for(int i=1;i<n;i++) s[i] = s[i-1]+a[i];
for(int i=0;i<n;i++) dp[i] = s[i];
for(int m=2;m<=M;m++){
int pos = n-1; // pos是最大的使得 dp[j][m-1] < s[i]-s[j]的j,当 i 单调减少的时候,pos也是单调减少的;
for(int i=n-1;i>=1;i--){
while(pos>=0 && dp[pos] >= s[i]-s[pos] ){
pos--;
}
if(pos>=0) dp[i] = min(dp[i], max(dp[pos],s[i]-s[pos]));
if(pos<n-1) dp[i] = min(dp[i],max(dp[pos+1],s[i]-s[pos+1]));
}
}
return dp[n-1];
}
};