dp[i][k]
表示将数组 A
中的前 i
个元素分成 k
个相邻的非空子数组,可以得到的最大分数。
状态转移方程:
dp(i, k) = max(dp(j, k - 1) + average(j + 1, i))
dp(i, 0) = average(0, i)
第一遍写代码,以正确为主。为了方便处理,将A数组的下标都加了1 ,放在temp数组里面了,反正dp都O(n^2),也不在乎这O(n)了。。
class Solution {
public double largestSumOfAverages(int[] A, int K) {
double[][] dp = new double[A.length + 1][K + 1];
int[] temp = new int[A.length+1];
temp[0] = 0;
for (int i = 0; i < A.length; i++)
temp[i+1] = A[i];
for (int i = 1; i <= A.length; i++) {
dp[i][1] = average(1, i, temp);
}
for (int k = 2; k <= K; k++) { //分成几组
for (int i = k; i < dp.length; i++) { //遍历数
for (int j = 1; j < i; j++) { //更新dp
dp[i][k] = Math.max(dp[j][k-1] + average(j+1, i, temp), dp[i][k]);
}
}
}
/*
for (int i = 0; i < dp.length; i++) {
for (int j = 0; j < dp[0].length; j++) {
System.out.print(dp[i][j]+" ");
}
System.out.println();
}*/
return dp[A.length][K];
}
public double average(int i, int j, int[] temp) {
double sum = 0;
for (int k = i; k <= j; k++) {
sum += temp[k];
}
return sum / (j - i + 1);
}
}
分析:
dp矩阵:
0.0 0.0 0.0 0.0
0.0 9.0 0.0 0.0
0.0 5.0 10.0 0.0
0.0 4.0 10.5 12.0
0.0 3.75 11.0 13.5
0.0 4.8 12.75 20.0
求第j列的时候只需要知道第j-1列dp,dp可以降维
求dp这三层循环还有求平均数的一层循环,时间复杂度很高,跑了59ms。
优化
用前缀和预处理,将平均数这层循环优化成常数时间,用滚动数组优化空间
官方题解
class Solution {
public double largestSumOfAverages(int[] A, int K) {
int N = A.length;
double[] P = new double[N+1];
for (int i = 0; i < N; ++i)
P[i+1] = P[i] + A[i];
double[] dp = new double[N];
//预处理,dp[i] -> i ~ N -1 不进行任何划分的平均值
for (int i = 0; i < N; ++i)
dp[i] = (P[N] - P[i]) / (N - i);
//将数组分k次(k为0不划分)
for (int k = 0; k < K-1; ++k)
for (int i = 0; i < N; ++i)
for (int j = i+1; j < N; ++j) //j ~ N-1 不做划分
dp[i] = Math.max(dp[i], (P[j]-P[i]) / (j-i) + dp[j]);
return dp[0];
}
}
- 时间复杂度:O(K * N2),其中 N是数组
A
的长度。 - 空间复杂度:O(N)