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/