LeetCode 410. 分割数组的最大值 (DP的优化、决策单调性、滚动数组)

分割数组的最大值

  • 一种复杂度过高的方案
    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[j1][m1],s[i]s[j1]) (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[j1],s[i]s[j1]一个是关于 j j j单调递增的函数,
      一个是关于 j j j单调递减的函数,所以那个我们要求的 j j j其实就是两个函数的交点极其临近点(因为不是连续的函数)。这可以用二分求出。
      时间复杂度: O ( m ∗ n ∗ l o g ( n ) ) O(m*n*log(n)) O(mnlog(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(nm)
    空间复杂度: 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];
    }
};

猜你喜欢

转载自blog.csdn.net/qq_44846324/article/details/108411329
今日推荐