[Leetcode] 813. Largest Sum of Averages 解题报告

这篇博客介绍了LeetCode 813题的解题思路,通过动态规划方法求解将数组分成K组时的最大平均数之和。博主认为这是一道中等难度的动态规划问题,提出了初始状态与状态转移方程,并指出可以通过预计算累积和优化求解过程,将空间复杂度降低到O(n)。最后,博主给出了算法的时间复杂度和空间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

We partition a row of numbers A into at most K adjacent (non-empty) groups, then our score is the sum of the average of each group. What is the largest score we can achieve?

Note that our partition must use every number in A, and that scores are not necessarily integers.

Example:
Input: 
A = [9,1,2,3,9]
K = 3
Output: 20
Explanation: 
The best choice is to partition A into [9], [1, 2, 3], [9]. The answer is 9 + (1 + 2 + 3) / 3 + 9 = 20.
We could have also partitioned A into [9, 1], [2], [3, 9], for example.
That partition would lead to a score of 5 + 2 + 6 = 13, which is worse.

 Note:

  • 1 <= A.length <= 100.
  • 1 <= A[i] <= 10000.
  • 1 <= K <= A.length.
  • Answers within 10^-6 of the correct answer will be accepted as correct.

思路

我感觉这道题目应该是一道中等难度的动态规划问题。首先明确一点,就是把组划分的越多,则平均数之和越大,所以只要K不超过A中的元素个数,那么的结果一定是对应划分成了K组,而不是比K小的组。

我们定义dp[i][k]表示将A[0]到A[i]这i+1个元素划分成为k组的话,平均数之和的最大值,然后推导递推公式:

1)如果k == 1,说明我们将这i+1个元素归为1组,所以dp[i][k] = avg(A[0],...A[i]);

2)如果k > 1,那么我么可以采用的策略是:将A[j], A[i]这i-j+1个数划分为1组,那么此时就需要将A[0],...A[j - 1]划分成为另外的k-1组(k - 1 <= j <= i)。在这所有的划分方法中,我们需要取使得dp[i][k]达到最大值的那种划分,所以dp[i][k] = max(dp[j - 1][k - 1] + avg(A[j],...A[i])), k - 1 <= j <= i。最后得到的dp[n - 1][K]即为所求。

由于我们需要求不同区间的平均数,所以在程序的第一步,我们首先利用O(n)的时间复杂度计算出A数组的累积和,这样在后面就可以在O(1)时间内求出任意区间内数值的平均值了。

算法的时间复杂度是O(kn^2),空间复杂度是O(kn),但是注意到dp[i][k]之和dp[j][k - 1]有关,其中k - 1 <= j <= i。所以实际上我们还可以进一步优化,将空间复杂度降低到O(n),这一步就留给读者了^_^。

代码

class Solution {
public:
    double largestSumOfAverages(vector<int>& A, int K) {
        // step 1: calculate the accumulated sums of A
        int n = A.size();
        vector<int> sums(n, 0);
        sums[0] = A[0];
        for (int i = 1; i < n; ++i) {
            sums[i] = sums[i - 1] + A[i];
        }
        // step 2: calculate the largest sum of averages using DP
        // dp[i][k] means the largest sum of averages in A[0, i] after partitioning in k groups
        vector<vector<double>> dp(n, vector<double>(K + 1, 0.0));
        for (int k = 1; k <= K; ++k) {
            for (int i = 0; i < n; ++i) {
                if (k == 1) {                               // treat all the elements in one group
                    dp[i][k] = sums[i] / static_cast<double>(i + 1);
                }
                else if (k > i + 1) {                       // less than k elements, so impossible
                    continue;
                }
                else {      // 1 < k <= i + 1
                    for (int j = k - 1; j <= i; ++j) {      // try to group A[j], ...A[i] together
                        double part1 = dp[j - 1][k - 1];
                        double part2 = (sums[i] - sums[j - 1]) / static_cast<double>(i - j + 1);
                        if (dp[i][k] < part1 + part2) {
                            dp[i][k] = part1 + part2;
                        }
                    }
                }
            }
        }
        return dp[n - 1][K];
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值