题目链接
区间动态规划
思路:动态规划
分析:如果n等于1,那么明显,不需要花费现金
如果n等于2,那么花费现金最小是1
如果n等于3,那么花费现金是2
.。。。。
n,如果我们猜x,如果对了,显然就没了,但是如果小了,那么也就是需要在x+1,到n中继续猜测,如果大了,那么也就是继续在1,x-1中猜,那么我们可以定义一个dp[i][j]表示在i到j中猜中所需要的最少的现金。
i==j的时候,也就是只有一个数,那么显然不用花费现金
i>j的时候,此时不存在,也就是不用猜,那么也就不用花费现金
所以i<j
并且dp[i][j]初始化为 j+dp[i][j-1]
那么在i到j的中间,我们猜测一个x,也就是说 i<x<j,那么三种情况,
第一:x正好中了,也就是dp[i][j]不变;
第二:x大了,也就是dp[i][j] = x+dp[i][x-1]
第三:x小了,也就是dp[i][j] = x+dp[x+1][j]
这三种情况都可能出现,但是要保证现金一定够可以猜中的,那么dp[i][j]等于上面二三种情况中最大的与自身比最小的那个
而且,可以看出,这里的dp[i][j]可以划分为更小的子问题,也就是可以划分为 i — x-1 x+1 ------ j的问题。
那么我们需要保证i—x-1 x+1-----j 是已经得出了结果的,那么我们需要i从大到小移动,j从i+1到n移动。
代码:
class Solution {
public int getMoneyAmount(int n) {
int[][] dp = new int[n+1][n+1];
//i是从大到小 j是从i+1到n
for(int i = n-1;i>=1;i--){
for(int j = i+1;j<=n;j++){
//j猜错了,j大了,这里的j 是 i+1~n,前面的是算好了的
//这里是为了当k=j的时候,k+1有越界的问题,所以提前算好一下
dp[i][j] = j + dp[i][j-1];
for(int k = i ; k<j ; k++){
//所有的最大的代价中最小的
dp[i][j] = Math.min(dp[i][j],k+Math.max(dp[i][k-1],dp[k+1][j]));
}
}
}
return dp[1][n];
}
}
思路二:动态规划,以长度为最外层循环
这个动态规划代码更好理解一些。
代码:
class Solution {
public int getMoneyAmount(int n) {
int[][] dp = new int[n+1][n+1];
//区间长度
for(int len = 2 ; len<=n ; len++){
//起始点
for(int start = 1; start + len -1 <=n;start++){
//结束点
int end = start + len - 1;
//初始化dp[start][end],选取区间的第一个,并且是猜错的情况,此时肯定是猜小了
dp[start][end] = start + dp[start+1][end];
//从start+1开始遍历
for(int k = start+1 ; k < end; k++){
//当前猜错的情况,并且需要花费的最大的金额
int cur = k + Math.max(dp[start][k-1],dp[k+1][end]);
//选择最大金额的最小值
dp[start][end] = Math.min(dp[start][end], cur);
}
}
}
return dp[1][n];
}
}
好好学习。
不打扰是我的温柔。