Dynamic Programming学习笔记 (38) - 分隔数组以得到最大和 (力扣# 1043)

136 阅读1分钟

本题出自力扣题库第1043题。题面大意如下:

给定一个整数数组arr,将该数组分隔为长度最多为k的一些(连续)子数组。分隔完成后,每个子数组的中的所有值都会变为该子数组中的最大值。 返回将数组分隔变换后能够得到的元素最大和。

示例:

输入:arr = [1,15,7,9,2,5,10], k = 3
输出:84
解释:
因为 k=3 可以分隔成 [1,15,7] [9] [2,5,10],结果为 [15,15,15,9,10,10,10],和为 84,是该数组所有分隔变换后元素总和最大的。

题解:

这是一个一维数组的基本DP应用,从题意出发可以很容易地得到以下的DP表达式:

F(i) =  max (
    max(arr[i])       * 1 + F(i + 1)
    max(arr[i] + 1) * 2 + F(i + 2)
    max(arr[i] + 2) * 3 + F(i + 3)
    ...
    max(arr[i] + k - 1) * k + F(i + k)
)

这里i是数组下标,F(i)返回的是从i开始的子数组按题面要求分割后的最大元素和,我们使用一维DP数组及一个单层的循环,按照数组下标从大到小依次计算DP数组中各个元素的值,循环完成后,DP[0]中的数值就是问题的答案。

Java代码如下:

class Solution {
    public int maxSumAfterPartitioning(int[] arr, int k) {
        int N = arr.length;
        int[] dp = new int[N + 1];

        for (int i = N - 1; i >= 0; i--) {
            int max = arr[i] + dp[i + 1];
            int maxElement = arr[i];
            for (int j = 2; (j <= k) && (i + j - 1 < N)  ; j++) {
                maxElement = Math.max(maxElement, arr[i + j - 1]);
                int sum = maxElement * j + dp[i + j];
                max = Math.max(max, sum);
            }
            dp[i] = max;
        }
        return dp[0];
    }
}