题目描述:
给出整数数组 A,将该数组分隔为长度最多为 K 的几个(连续)子数组。分隔完成后,每个子数组的中的值都会变为该子数组中的最大值。
返回给定数组完成分隔后的最大和。
示例:1
输入:A = [1,15,7,9,2,5,10], K = 3
输出:84
解释:A 变为 [15,15,15,9,10,10,10]
提示:
1 <= K <= A.length <= 500
0 <= A[i] <= 10^6
因为 k=3 可以分隔成 [1,15,7] [9] [2,5,10],结果为 [15,15,15,9,10,10,10],和为 84,是该数组所有分隔变换后元素总和最大的。
若是分隔成 [1] [15,7,9] [2,5,10],结果就是 [1, 15, 15, 15, 10, 10, 10] 但这种分隔方式的元素总和(76)小于上一种。
示例 2:
输入:arr = [1,4,1,5,7,3,6,1,9,9,3], k = 4
输出:83
示例 3:
输入:arr = [1], k = 1
输出:1
思路
动态规划
dp[i]:数组的前 i 个数即 nums[【0,1…i-1】,被切了 Y−1 刀,分割成 Y 个数组,满足每个数组的个数最大值不超过 K,每个数组的值变成最大值,分割后的最大和,如上图,当被分成Y=3 个部分时,第一部分的最大值为 15,第二部分为 9,第三部分 10,每一部分的每个值都上升为当前部分的局部 max,红色字体为新的值,累加后,求其最大值
求 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),
其中 MAX 是 nums[j...i−1] 范围内的局部最大值,一旦找到最大值,该范围内的所有值都改成这个局部最大值 MAX,
其中 0 =< j< i
代码
public int maxSumAfterPartitioning(int[] A, int K) {
int n = A.length;
int[] dp = new int[n + 1];
//核心思想是每到一个数,就把这个数放到一个新的框子里,然后开始往前调整
//框子里的值为进来的数的最大值
//往前取,最多只能取到i-k+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];
}