vlambda博客
学习文章列表

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

欢迎阅读、点赞、转发、订阅,你的举手之间,我的动力源泉。


定义状态

dp[i]:数组的前i个数即nums[0,1...i-1],被切了K-1刀,分割成K个数组,每个数组的值变成最大值,分割后的最大和,如上图,当被分成K=3个部分时,第一部分的最大值为15,第二部分为9,第三部分10,每一部分的每个值都上升为当前部分的局部max,红色字体为新的值,累加后,求其最大值

转移方程

要想求dp[i],这是数组的前i个数即nums[0,1...i-1],被切了K-1WWW刀,分割成K个数组,每个数组的值变成最大值,分割后的最大和

  • dp[i-1],表示数组的前i个数即nums[0,1…i-2],第二部分是nums[i-1],也就是说 dp[i-1]+max(nums[i-1])*(i-(i-1))

  • dp[i-2],表示数组的前i-1个数即nums[0,1…i-3],第二部分是nums[i-2…i-1],也就是说 dp[i-2]+max(nums[i-2…i-1])*(i-(i-2))

  • dp[i-3],表示数组的前i-2个数即nums[0,1…i-4],第二部分是nums[i-3…i-1],也就是说 dp[i-3]+max(nums[i-3…i-1])*(i-(i-3))

  • dp[0],表示数组的前1个数即nums[0,0],第二部分是nums[0…i-1],也就是说 dp[0]+max(nums[0…i-1])*(i-(0))

求上面的的最大值

可以推导出dp[i]=max(dp[i],dp[j]+(i-j)*MAX),其中MAXnums[j...i-1]范围内的局部最大值,一旦找到最大值,该范围内的所有值都改成这个局部最大值MAX,其中0=<j<i

初始化边界

i-j如果大于K前面的部分已经被分割成了K部分了,后面nums[i...n]这部分将没有办法被涵盖进来,一个条件:i-j<=K

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

dp初始化的时候容量为n+1,要求的dp[n]表示数组的前n个数即nums[0,1...n],被切了K-1刀,分割成K个数组,每个数组的值变成最大值,分割后的最大和

编码技巧

  • i从做到有遍历,j起始为i-1从右往左遍历

  • 注意记录局部的最大值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];
    }

总结

  • 动态规划的题目,需要想到一些基本的情况,可以像数学归纳法一样思考