Description
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组,然后计算每组的平均值,求和使得平均值之和最小。
dp[k][i]表示前i+1个元素(0~i)最多分k个组是平均数和最大,然后就是自己手动写一个表可以简单推导一下.表格如下:
k \ i 0 1 2 3 4
0 9.00 5.00 4.00 3.75 4.80
1 9.00 10.00 10.50 11.00 12.75
2 9.00 10.00 12.00 13.50 20.00
- 自己认认真真打完表后很容易就可以推导dp的方程:
dp[k][i] = max(dp[k - 1][i], dp[k - 1][j] + (sum[j + 1, i] / (i - j)); (k > = 1, sum[j + 1, i]表示区间j+1到i中间所有数的和) - 当然求区间和的话我们可以做一下预处理保证sum[j+1,i]是O(1)时间就可以.
代码
class Solution {
public:
double largestSumOfAverages(vector<int>& A, int K) {
int n=A.size();
vector<double> sum(n+1,0);
for(int i=1;i<=n;i++){
sum[i]=A[i-1]+sum[i-1];
}
vector<vector<double>> dp(K,vector<double>(n,0));
for(int k=0;k<K;k++){
for(int i=0;i<n;i++){
dp[k][i]=k==0 ? sum[i+1]/(i+1):dp[k-1][i];
if(k>0){
for(int j=i-1;j>=0;j--){
dp[k][i]=max(dp[k][i],dp[k-1][j]+(sum[i+1]-sum[j+1])/(i-j));
}
}
}
}
return dp[K-1][n-1];
}
};
分析二
设dp[i][k]表示将数组中前i个元素分成k个相邻的非空子数组,可以得到的最大分数。dp[i][k]可以通过dp[i][k-1]推导而来,其中j<i,状态转移方程为:
dp[i][k]=max(dp[i][k],dp[i][k-1]+average(j+1,i))
dp[i][0]=average(0,i)
average(j+1,i)=(A[j+1]+A[j+2]+...+A[i])/(i-j)
average(j+1,i)可以通过累加数组得到。
进一步,假设dp[i][k]为第K层的结果,第K层的结果只与K-1层有关,因此可以使用滚动数组优化空间,即只使用两个一维数组。进一步,如果我们从后往前进行动态规划,即dp[i][k]表示数组A中从第i个元素开始到结尾A[i:]分成k个相邻的非空子数组,可以得到最大分数,状态转移方程将变为:
dp[i][k]=max(dp[i][k],dp[i][k-1]+average(i,j-1))
dp[i][0]=average(i,n-1)
其中j>i,那么在计算第k层结果,并且在i依次递增的时候,第k层的结果不会覆盖掉第k-1层的结果。因此我们最终只需要用一个一维数组,就能完成动态规划。倒过来以后,最终的结果就是dp[0]了。
代码二(python)
class Solution:
def largestSumOfAverages(self, A: List[int], K: int) -> float:
n=len(A)
sums=[0]
for i in range(n):
sums.append(sums[-1]+A[i])
dp=[0]*(n+1)
for i in range(n):
dp[i]=(sums[n]-sums[i])/(n-i)
for k in range(K-1):
for i in range(n):
for j in range(i+1,n):
dp[i]=max(dp[i],dp[j]+(sums[j]-sums[i])/(j-i))
return dp[0]