[Leetcode]1043. Partition Array for Maximum Sum

Description

Given an integer array A, you partition the array into (contiguous) subarrays of length at most K. After partitioning, each subarray has their values changed to become the maximum value of that subarray.
Return the largest sum of the given array after partitioning.

Example

Input: A = [1,15,7,9,2,5,10], K = 3
Output: 84
Explanation: A becomes [15,15,15,9,10,10,10]

Note

  1. 1 <= K <= A.length <= 500
  2. 0 <= A[i] <= 10^6

分析

  1. 对数组A进行切分,切分后的每个子数组长度最大为K
  2. 每个子数组可以被其包含的元素最大值替换,例如[1,2,3]可以替换成[3,3,3]
  3. 找到能够使数组A所有元素和最大的处理方式,并返回该最大值
  4. 数组的长度区间为[1,500],元素值的范围是[0,10^6]

通过对于题目的分析可以发现,这是一道求最优解的题目,这种题目的解法不是贪心就是DP。再加上这道题的最大规模是500,所以基本上可以确定是O(n^2)的复杂度。
我们先来找一个简单的例子:A=[1,2,3], K=3
这个case只有4种切法:

  1. [1,2,3] -> [3,3,3] -> 9 -> answer
  2. [1,2] [3] -> [2,2][3] -> 7
  3. [1] [2,3] -> [1][3,3] -> 7
  4. [1][2][3] -> [1][2][3] -> 6
    其实这里我已经把顺序按照从后向前切的方式排好了,[1,2,3]这个子数组独立出来之后,我们只关心当前这个子数组的状态和其之前的状态,即cur_sub_sum + pre_max_sum,这种只关心前面状态的方式就非常适合用dp来解了。
    我们声明一个长度为n+1的数组dp,dp[i]表示当前第i个元素A数组所能达到的最大和,dp[0]被初始化为0,dp[n+1]即最终结果。
class Solution(object):
    def maxSumAfterPartitioning(self, A, K):
        """
        :type A: List[int]
        :type K: int
        :rtype: int
        """
        n = len(A)
        dp = [0 for _ in range(n+1)]
        for i in range(1, n+1):
            m = -1
            for k in range(1, min(i, K)+1):
                m = max(m, A[i-k])
                dp[i] = max(dp[i], dp[i-k] + m*k)
        return dp[n]

我们还是以[1,2,3]来模拟一下整个过程:
当i=1时:
k = 1, m=1,此时dp[0]只能选择一个1
A: 1 2 3
dp: 0 1

当i=2时:
k=1时,m=2,此时dp[1]=max(dp[1], dp[0]+21)=2
A: 1 2 3
dp: 0 1 2
k=2时, m=2, 此时dp[1] = max(dp[1], d[0]+2
2) = 4
A: 1 2 3
dp: 0 1 4

当i=3时:
k=1时,m=3,此时dp[2]=max(dp[2], dp[0]+31)=3
A: 1 2 3
dp: 0 1 4 3
k=2时,m=3,此时dp[2]=max(dp[2], dp[0]+3
2)=6
A: 1 2 3
dp: 0 1 4 6
k=3时,m=3,此时dp[2]=max(dp[2], dp[0]+3*3)=9
A: 1 2 3
dp: 0 1 4 9

最终dp = [0,1,4,9]

在代码中可以看出子数组中的最大值m做了滚动处理,因此只需要维护一个变量即可。

你可能感兴趣的:([Leetcode]1043. Partition Array for Maximum Sum)