375. 猜数字大小 II
我们正在玩一个猜数游戏,游戏规则如下:
我从 1 到 n 之间选择一个数字。
你来猜我选了哪个数字。
如果你猜到正确的数字,就会 赢得游戏 。
如果你猜错了,那么我会告诉你,我选的数字比你的 更大或者更小 ,并且你需要继续猜数。
每当你猜了数字 x 并且猜错了的时候,你需要支付金额为 x 的现金。如果你花光了钱,就会 输掉游戏 。
给你一个特定的数字 n ,返回能够 确保你获胜 的最小现金数,不管我选择那个数字 。
示例 1:
输入:n = 10
输出:16
学习要点:
记忆化搜索:dp[l][r]在循环的时候是不赋值的,一定是得到最优解之后,才赋值为dp[l][r],然后给别的子问题用。自己还不是最优,怎么让别人也最优。
区间动态规划:
题解:
代码:记忆化搜索
class Solution { public: int dp[205][205]; int dfs(int l,int r) { if (l>=r) return 0; if (dp[l][r]>0) return dp[l][r]; int sum=0x7fffffff; for(int i=l;i<=r;i++) sum=min(sum,max(dfs(l,i-1),dfs(i+1,r))+i); dp[l][r]=sum; // 是得到最优值sum才能赋值的,不能在中间得到解。 return dp[l][r]; } int getMoneyAmount(int n) { memset(dp,0,sizeof(dp)); return dfs(1,n); } };
改写成区间DP:
class Solution { public: int dp[205][205]; int getMoneyAmount(int n) { // 改写成:区间dp for(int len=1;len<=n;len++) // dp[i][j]:起始点i,终点为j的区间 for(int i=1;i+len-1<=n;i++) { int j=i+len-1; if(len==1) {dp[i][j]=0; continue;} dp[i][j]=0x7fffffff; for(int k=i;k<=j;k++) dp[i][j]=min(dp[i][j],max(dp[i][k-1],dp[k+1][j])+k); } return dp[1][n]; } };