我们将给定的数组 A
分成 K
个相邻的非空子数组 ,我们的分数由每个子数组内的平均值的总和构成。计算我们所能得到的最大分数是多少。
注意我们必须使用 A 数组中的每一个数进行分组,并且分数不一定需要是整数。
示例: 输入: A = [9,1,2,3,9] K = 3 输出: 20 解释: A 的最优分组是[9], [1, 2, 3], [9]. 得到的分数是 9 + (1 + 2 + 3) / 3 + 9 = 20. 我们也可以把 A 分成[9, 1], [2], [3, 9]. 这样的分组得到的分数为 5 + 2 + 6 = 13, 但不是最大值.
说明:
1 <= A.length <= 100
.1 <= A[i] <= 10000
.1 <= K <= A.length
.- 答案误差在
10^-6
内被视为是正确的。
思路:采用带记忆数组的递归,维护一个三维数组memo,其中memo[i][j][k]表示从下标i到下标为j需要分成k组的最大平均值是多少。那么这是一个递归的过程,每次把需分成k组分为第一组和剩下的k-1组,那么第一组计算从下标i为left~(right - (K - 1))的子数组平均值和(相当于每次加一个数字,然后除以已加的数字的个数)和递归调用剩下的i+1开始的k-1个子数组的和中取最大,核心代码如下:
double tmp = 0.0;
int count = 1;
double res = 0.0;
for (int i = left; i <= (right - (K - 1)); i++) {
tmp += A[i];
res = max(res, tmp / count + largestSumOfAveragesCore(i + 1, right, K - 1, A,memo));
count++;
}
然后用一个记忆数组memo[left][right][k]保存计算过得从下标为left到下标为right的子数组中分为k组的最大平均值,最后返回所有memo值中最大的值即可。
参考代码:
class Solution {
public:
double largestSumOfAveragesCore(int left, int right, int K, vector<int>& A, vector<vector<vector<double>>> &memo) {
if (memo[left][right][K] != -1) {
return memo[left][right][K];
}
if (K == 1) {
double cur = 0.0;
for (int i = left; i <= right; i++) {
cur += A[i];
}
memo[left][right][K] = cur / (right - left + 1);
return memo[left][right][K];
}
if ((right - left + 1) < K) {
return 0.0;
}
if ((right - left + 1) == K) {
double cur = 0.0;
for (int i = left; i <= right; i++) {
cur += A[i];
}
memo[left][right][K] = cur;
return memo[left][right][K];
}
double tmp = 0.0;
int count = 1;
double res = 0.0;
for (int i = left; i <= (right - (K - 1)); i++) {
tmp += A[i];
res = max(res, tmp / count + largestSumOfAveragesCore(i + 1, right, K - 1, A,memo));
count++;
}
memo[left][right][K] = res;
return memo[left][right][K];
}
double largestSumOfAverages(vector<int>& A, int K) {
double res = 0.0;
vector<vector<vector<double>>> memo(A.size(), vector<vector<double>>(A.size(),vector<double>(K+1,-1)));
res = largestSumOfAveragesCore(0, A.size() - 1, K, A,memo);
return res;
}
};