1043. 分隔数组以得到最大和
难度:中等
时间:2023/04/19
给你一个整数数组 arr,请你将该数组分隔为长度 最多 为 k 的一些(连续)子数组。分隔完成后,每个子数组的中的所有值都会变为该子数组中的最大值。
返回将数组分隔变换后能够得到的元素最大和。本题所用到的测试用例会确保答案是一个 32 位整数。
示例 1:
输入:arr = [1,15,7,9,2,5,10], k = 3
输出:84
解释:数组变为 [15,15,15,9,10,10,10]
示例 2:
输入:arr = [1,4,1,5,7,3,6,1,9,9,3], k = 4
输出:83
示例 3:
输入:arr = [1], k = 1
输出:1
提示:
1 <= arr.length <= 5000 <= arr[i] <= 10^91 <= k <= arr.length
解题思路:
-
题意 给定数组A,将数组分割成若干个子数组,每个子数组的长度不超过K,并且子数组中的每个数字都变为其中的最大值。问整个数组的最大值之和是多少?
-
思路 分割的位置会影响之后的可分割的位置,这是一个动态规划问题。
设dp[i]表示前i个元素能达到的最大和。考虑到长度最大为K,那么dp[i]可以由dp[i-K] ~ dp[i-1]推导而来,即状态转移为:
dp[i] = max( dp[j] + max(A[j:i]) * (i - j) ),其中i - K <= j <= i - 1
PS.一开始我想着把区间最大值预处理出来,但时间复杂度是O(N^2)。后来发现这一步是没有必要的,因为通过将对j的遍历方向变为逆序,那么最大值可以同时求出来,时间复杂度是O(NK),很明显后者更好。
class Solution {
public:
int maxSumAfterPartitioning(vector<int>& A, int K) {
const int n = A.size();
// dp[i] : 以nums[i]为切割的结尾,目前切割所能得到的最大值为dp[i]
vector<int> dp(n + 1, 0);
for (int i = 1; i <= n; ++i) {
int maxN = -1;
for (int j = i - 1; j >= max(i - K, 0); --j) {
maxN = max(maxN, A[j]);
dp[i] = max(dp[i], dp[j] + maxN * (i - j));
}
}
return dp[n];
}
};