前言
动规、归在中等类,但是比较难吧
正文
问题来源
本问题来自leetcode上的813题。这道题自己并没能独立解出来,参考网上的博文。Leetcode 813
问题描述
数组的每个索引做为一个阶梯,第 i个阶梯对应着一个非负数的体力花费值 costi。
每当你爬上一个阶梯你都要花费对应的体力花费值,然后你可以选择继续爬一个阶梯或者爬两个阶梯。
您需要找到达到楼层顶部的最低花费。在开始时,你可以选择从索引为 0 或 1 的元素作为初始阶梯。
示例 1:
输入: cost = [10, 15, 20]
输出: 15
解释: 最低花费是从cost[1]开始,然后走两步即可到阶梯顶,一共花费15。
示例 2:
输入: cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1]
输出: 6
解释: 最低花费方式是从cost[0]开始,逐个经过那些1,跳过cost[3],一共花费6。
分析:
当看到Note里面A的lenth最大值是100的时候,这道题如果用dfs的话可能会超时(没有去试),用dp的话目测应该需要三重循环,因此此时大概就会想到用dp[k][i]表示前i+1个元素(0~i)最多分k个组是平均数和最大,然后就是自己手动写一个表可以简单推导一下.表格如下:
k\i | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
0 | 9 | 5 | 4 | 3.75 | 4.8 |
0 | 9 | 10 | 10.5 | 11 | 12.75 |
0 | 9 | 10 | 12 | 13.5 | 20 |
自己认认真真打完表后很容易就可以dp的方程:
dp[k][i] = Math.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)时间就可以
C代码如下:
#define max(x,y) ((x)>(y)?(x) : (y))
double largestSumOfAverages(int* A, int ASize, int K) {
double **dp = NULL;
int i,j,k;
double ret,temp;
int *sum;
dp = (double**)malloc((K)*sizeof(double*));
for(i=0;i<K;i++)
{
dp[i] = (int*)malloc(ASize*sizeof(double));
}
sum = (int*)malloc(ASize*sizeof(int));
sum[0] = A[0];
dp[0][0] = A[0];
for(i=1;i<ASize;i++)
{
sum[i] = sum[i-1] + A[i];
dp[0][i] = sum[i] / (double)(i+1);
}
for(i=1;i<K;i++)
{
//dp[i] = max(dp[i-1],dp[i-2] + nums[i-1]);
for(j=0;j<ASize;j++)
{
temp = dp[i-1][j];
for(k=0;k<j;k++)
{
temp = max(temp,dp[i-1][k]+(sum[j]-sum[k])/(double)(j-k));
}
dp[i][j] = temp;
}
}
ret = dp[K-1][ASize-1];
for(i=0;i<K;i++)
{
free(dp[i]);
}
free(dp);
free(sum);
dp = NULL;
return ret;
}
Java
class Solution {
public double largestSumOfAverages(int[] A, int K) {
int len = A.length;
double[] pre = new double[len + 1]; //区间和预处理 sum[i, j] = pre[j + 1] - pre[i]
for (int i = 1; i <= len; ++i) {
pre[i] = pre[i - 1] + A[i - 1];
}
double[][] dp = new double[K][len];
for (int k = 0; k < K; ++k) {
for (int i = 0; i < len; ++i) {
dp[k][i] = k == 0 ? pre[i + 1]/(i + 1) : dp[k - 1][i];
if (k > 0) {
for (int j = i - 1; j >= 0; --j) {
dp[k][i] = Math.max(dp[k][i], dp[k - 1][j] + (pre[i + 1] - pre[j + 1]) / (i - j));
}
}
}
}
return dp[K - 1][len - 1];
}
}
总结:
目前讨论区中仅仅只有DFS和时间复杂度为O(KNN)的解法。
结语
闲来无事的话,多练习练习,做做题。