最大平均值和的分组 | 动态规划

题目大意:
将给定的数组 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]


(完)

posted @ 2022-11-29 10:43  izcat  阅读(118)  评论(0编辑  收藏  举报