813. Largest Sum of Averages

https://leetcode.com/problems/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.

算法思路:

方法1:记忆化搜索

  • prefix sum技术
  • 定义位置p与分割k的状态函数dfs,见代码注释部分,将大的问题转换成子问题
  • 记忆化数组避免子问题重复计算
//O(k*n^2)  O(n^2+n) = O(n^2)
//Runtime: 8 ms, 98.34%
//Memory Usage: 7.9 MB, 60.78%
//dfs(p, k): when in position p and at most k adjacent group, how largest score we can achieve
class Solution {
public:
    double largestSumOfAverages(vector<int>& A, int K) {
        int n = A.size();
        if(K >= n) return accumulate(A.begin(), A.end(), 0);
        
        vector<int> sum(n + 1, 0);
        for(int i = 0; i < n; i++) sum[i + 1] = sum[i] + A[i];
        
        vector<vector<double>> memo(n, vector<double>(K + 1, -1));
        return dfs(A, sum, memo, n - 1, K);
    } 
private:
    double dfs(const vector<int>& A, const vector<int>& sum, 
               vector<vector<double>>& memo, int p, int k) {
        
        if(k == 1) return sum[p + 1] / ((p + 1) * 1.0);
        if(p + 1 <= k) return sum[p + 1];
        
        if(memo[p][k] != -1) return memo[p][k];
        
        double res = A[p];
        int curSum = 0;
        for(int i = p - 1; i >= 0; i--) {
            curSum += A[i + 1];
            res = max(res, curSum * 1.0 / (p - i) + dfs(A, sum, memo, i, k - 1));    
            if(i + 1 <= k - 1) break; //not satisfy this condition,we can just break
        }

        return memo[p][k] = res;
    }
};

改进一下内存,使用A来避免sum的申请,但是破坏了原始数据

//O(k*n^2)  O(n^2)
//Runtime: 8 ms, 98.34%
//Memory Usage: 7.9 MB, 63.40% 
//dfs(p, k): when in position p and at most k adjacent group, how largest score we can achieve
class Solution {
public:
    double largestSumOfAverages(vector<int>& A, int K) {
        int n = A.size();
        if(K >= n) return accumulate(A.begin(), A.end(), 0);
        
        for(int i = 1; i < n; i++) A[i] += A[i - 1];
        
        vector<vector<double>> memo(n, vector<double>(K + 1, -1));
        return dfs(A, memo, n - 1, K);
    } 
private:
    double dfs(const vector<int>& A, vector<vector<double>>& memo, int p, int k) {
        if(k == 1) return A[p] / ((p + 1) * 1.0);
        if(p + 1 <= k) return A[p];
        
        if(memo[p][k] != -1) return memo[p][k];
        
        double res = 0;
        int curSum = 0;
        for(int i = p - 1; i >= 0; i--) {
            curSum = A[p] - A[i];
            res = max(res, curSum * 1.0 / (p - i) + dfs(A, memo, i, k - 1));    
            if(i + 1 <= k - 1) break; //not satisfy this condition,we can just break
        }

        return memo[p][k] = res;
    }
};

方法2:改造成dp

//dp[p]: when in position p how largest scores we can get within the k parts
class Solution {
public:
    double largestSumOfAverages(vector<int>& A, int K) {
        int n = A.size();
        if(K >= n) return accumulate(A.begin(), A.end(), 0);
        vector<int> sum(n + 1, 0);
        for(int i = 0; i < n; i++) sum[i + 1] = sum[i] + A[i];
        
        vector<double> dp(n, 0);
        for(int i = 0; i < n; i++) dp[i] = sum[i + 1] * 1.0 / (i + 1) ;
        
        for(int k = 1; k < K; k++) {
            for(int p = n - 1; p >= 0; p--) {
                for(int i = p - 1; i >= 0; i--) {
                    dp[p] = max(dp[p], (sum[p + 1] - sum[i + 1]) * 1.0 / (p - i) + dp[i]);
                }
            }
        }
        
        return dp[n - 1];
    }
};

参考资料:

https://leetcode.com/problems/largest-sum-of-averages/solution/

https://www.bilibili.com/video/av31348968/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值