[LeetCode]动态规划解分割数组II[Arctic Fox]

75 篇文章 0 订阅

解题思路:

写本题,源自看到的官方的一句描述 “「将数组分割为 m 段,求……」是动态规划题目常见的问法。”,让我想起了之前写的 1043. 分隔数组以得到最大和,早期写的题解,风格更像一种草稿,但还是有很多扣友鼓励似的阅读点赞,感谢感谢,笔芯~

image-20200728190440746.png

image-20200728211404716.png{:width=“350px”}{:align=“left”}

定义状态

d p [ i ] dp[i] dp[i]:数组的前 i i i 个数即 n u m s [ 0 , 1... i − 1 ] nums[0,1...i-1] nums[0,1...i1],被切了 Y − 1 Y-1 Y1 刀,分割成 Y Y Y 个数组,满足每个数组的个数最大值不超过 K K K,每个数组的值变成最大值,分割后的最大和,如上图,当被分成 Y = 3 Y=3 Y=3 个部分时,第一部分的最大值为 15 15 15,第二部分为 9 9 9,第三部分 10 10 10,每一部分的每个值都上升为当前部分的局部 m a x max max,红色字体为新的值,累加后,求其最大值

转移方程

image-20200728211805764.png{:width=“450px”}{:align=“left”}

要想求 d p [ i ] dp[i] dp[i],这是数组的前 i i i 个数即 n u m s [ 0 , 1... i − 1 ] nums[0,1...i-1] nums[0,1...i1],被切了 Y − 1 Y-1 Y1 刀,分割成 Y Y Y 个数组,满足每个数组的个数最大值不超过 K K K,每个数组的值变成最大值,分割后的最大和

  • d p [ i − 1 ] dp[i-1] dp[i1],表示数组的前 i i i 个数即 n u m s [ 0 , 1... i − 2 ] nums[0,1...i-2] nums[0,1...i2],第二部分是 n u m s [ i − 1 ] nums[i-1] nums[i1],也就是说 d p [ i − 1 ] dp[i-1] dp[i1] + m a x ( n u m s [ i − 1 ] ) max(nums[i-1]) max(nums[i1])* ( i − ( i − 1 ) ) (i-(i-1)) (i(i1))
  • d p [ i − 2 ] dp[i-2] dp[i2],表示数组的前 i − 1 i-1 i1 个数即 n u m s [ 0 , 1... i − 3 ] nums[0,1...i-3] nums[0,1...i3],第二部分是 n u m s [ i − 2... i − 1 ] nums[i-2...i-1] nums[i2...i1],也就是说 d p [ i − 2 ] dp[i-2] dp[i2] + m a x ( n u m s [ i − 2... i − 1 ] ) max(nums[i-2...i-1]) max(nums[i2...i1]) * ( i − ( i − 2 ) ) (i-(i-2)) (i(i2))
  • d p [ i − 3 ] dp[i-3] dp[i3],表示数组的前 i − 2 i-2 i2 个数即 n u m s [ 0 , 1... i − 4 ] nums[0,1...i-4] nums[0,1...i4],第二部分是 n u m s [ i − 3... i − 1 ] nums[i-3...i-1] nums[i3...i1],也就是说 d p [ i − 3 ] dp[i-3] dp[i3] + m a x ( n u m s [ i − 3... i − 1 ] ) max(nums[i-3...i-1]) max(nums[i3...i1]) * ( i − ( i − 3 ) ) (i-(i-3)) (i(i3))
  • d p [ 0 ] dp[0] dp[0],表示数组的前 1 1 1 个数即 n u m s [ 0 , 0 ] nums[0,0] nums[0,0],第二部分是 n u m s [ 0... i − 1 ] nums[0...i-1] nums[0...i1],也就是说 d p [ 0 ] dp[0] dp[0] + m a x ( n u m s [ 0... i − 1 ] ) max(nums[0...i-1]) max(nums[0...i1]) * ( i − ( 0 ) ) (i-(0)) (i(0))

求上面的的最大值

可以推导出 d p [ i ] dp[i] dp[i]= m a x max max( d p [ i ] dp[i] dp[i] d p [ j ] + ( i − j ) ∗ M A X dp[j]+(i-j)*MAX dp[j]+(ij)MAX),其中 M A X MAX MAX n u m s [ j . . . i − 1 ] nums[j...i-1] nums[j...i1] 范围内的局部最大值,一旦找到最大值,该范围内的所有值都改成这个局部最大值 M A X MAX MAX,其中 0=< j j j< i i i

初始化边界

i − j i-j ij 如果大于 K K K,后面 n u m s [ i . . . n ] nums[i...n] nums[i...n] 这部分将没有办法被涵盖进来,一个条件: i − j i-j ij<= K K K

j j j>=0,这个没啥好说的

d p dp dp 初始化的时候容量为 n + 1 n+1 n+1,要求的 d p [ n ] dp[n] dp[n] 表示数组的前 n n n 个数即 n u m s [ 0 , 1... n ] nums[0,1...n] nums[0,1...n],被切了 Y − 1 Y-1 Y1 刀,分割成 Y Y Y 个数组,满足每个数组的个数最大值不超过 K K K,每个数组的值变成最大值,分割后的最大和

编码技巧

  • i i i 从左到右遍历, j j j 起始为 i − 1 i-1 i1 从右往左遍历
  • 注意记录局部的最大值 M A X MAX MAX

完整代码

    public int maxSumAfterPartitioning(int[] A, int K) {
        int n = A.length;
        int[] dp = new int[n + 1];
        for (int i = 0; i <= n; i++) {
            int j = i - 1;
            int max = dp[i];
            while ((i - j) <= K && j >= 0) {
                max = Math.max(max, A[j]);
                dp[i] = Math.max(dp[i], dp[j] + (i - j) * max);
                j--;
            }
        }
        return dp[n];
    }
class Solution {
public:
    int maxSumAfterPartitioning(vector<int>& A, int K) {
        // f[i] = max(f[j] + (i-j)*max(A[j..i]))

        int n = A.size();
        vector<int> f(n+1);
        for (int i = 0; i <= n; i++) {
            int curMax = 0;
            // consider past integers [j...i]
            for (int j = i-1; (i-j)<=K && j>=0; j--) {
                curMax = max(curMax, A[j]);
                f[i] = max(f[i], f[j] + (i-j)*curMax);
            }
        }
        return f[n];
    }
};

总结

  • 动态规划的题目,需要想到一些基本的情况,可以像数学归纳法一样思考
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值