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

题目

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)时间内求出任意区间内数值的平均值了。

扫描二维码关注公众号,回复: 914933 查看本文章

算法的时间复杂度是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];
    }
};

猜你喜欢

转载自blog.csdn.net/magicbean2/article/details/79893634