1. 程式人生 > 其它 >最大平均值和的分組 | 動態規劃

最大平均值和的分組 | 動態規劃

題目大意:
將給定的陣列 nums 分成 k 個相鄰的非空子陣列,使得由每個子陣列內的平均值的總和最大化。

資料範圍:
1 <= nums.length <= 100
1 <= nums[i] <= 10^4
1 <= k <= nums.length

https://leetcode.cn/problems/largest-sum-of-averages/

思路分析:
直接列舉每種劃分方案,最壞情況下共有C(100, 50)種組合,無法暴力計算。
拆分子問題,可以發現如果先解決將子陣列劃分為 k-1 段的最大平均和,合併剩餘部分為一段,則原問題答案為所有子問題解中的最優解。
從自頂向下的角度來看,結論是顯然的:將給定的陣列 nums 分成 k 個相鄰的非空子陣列,必然存在某個間斷點 s 使得 [s, n-1]為一段,而 average(nums[s:n]) + subproblem(nums[: s], k-1) 是最大的。
因而問題轉化為求解新的子問題:將給定的陣列 nums[: s] 分成 k-1 個相鄰的非空子陣列,使得由每個子陣列內的平均值的總和最大化。
實際可以採用自下而上的合併方式求解。

AC程式碼:

class Solution:
    def largestSumOfAverages(self, nums: List[int], k: int) -> float:
        n = len(nums)
        # dp[i][j] nums[:i] 劃分j段 平均和
        dp = [[0]*(k+1) for _ in range(n)]

        for i in range(n):
            dp[i][1] = sum(nums[:i+1]) / (i+1)

        for i in range(n):
            for j in range(2, min(i+1, k)+1):  # 注意上下界
                for s in range(i):
                    dp[i][j] = max(dp[i][j], dp[s][j-1]+sum(nums[s+1:i+1])/(i-s))  # [s+1:i+1]區間內總和可以預處理
        
        return dp[n-1][k]


(完)