375. 猜数字大小 II 力扣(中等) 区间动态规划、记忆化搜索

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];
    }
};

 

posted on 2021-11-12 19:52  Yxter  阅读(62)  评论(0编辑  收藏  举报

导航