[Leetcode] 375. Guess Number Higher or Lower II 解题报告

来源:互联网 发布:龙渊网络app 编辑:程序博客网 时间:2024/06/06 17:04

题目

We are playing the Guess Game. The game is as follows:

I pick a number from 1 to n. You have to guess which number I picked.

Every time you guess wrong, I'll tell you whether the number I picked is higher or lower.

However, when you guess a particular number x, and you guess wrong, you pay $x. You win the game when you guess the number I picked.

Example:

n = 10, I pick 8.First round:  You guess 5, I tell you that it's higher. You pay $5.Second round: You guess 7, I tell you that it's higher. You pay $7.Third round:  You guess 9, I tell you that it's lower. You pay $9.Game over. 8 is the number I picked.You end up paying $5 + $7 + $9 = $21.

Given a particular n ≥ 1, find out how much money you need to have to guarantee a win.

思路

做了这道题目,我才发现Dynamic Programming和DFS + memorization的共通之处。其实这类题目的本质上就是一个问题可以分解为两个或者两个以上的规模更小的子问题的求解(当然能够分解的前提是这类问题具有最优子结构)。如果用简单的递归(也可以说是DFS),那么就会重复解决多个子问题,造成运行效率的低下。动态规划和带记忆的深度优先搜索分别提供了两种不同的解决方法:其中动态规划采用的是勤方法,也就是不管三七二十一,我先把所有的子问题都求解出来并且记录下来,然后在求解规模更大的问题的时候直接调用,是一种主动出击的方法;而带记忆的深度优先搜索则采用的是懒方法,也就是我直接试着求解最大规模的问题,求解的过程中如果需要求解规模更小的问题,首先查表看看该子问题是否已经被求解并且记录下来了,如果是则直接使用结果;否则就转而求解该子问题,并且将结果记录下来,这是一种被动反击的方法。

那么这两种策略孰优孰劣呢?当然是各有利弊需要具体问题具体分析了:动态规划不需要递归调用,运行效率高,代码简洁,但是在某些问题中,可能额外计算了不需要求解的很多子问题;带记忆的DFS绝不会多计算一个子问题,因为只有在需要计算的时候才展开计算,但是它实现中需要递归调用,代码也显得复杂一些。

对于本题目,我们定义一个二维数组dp,其中dp[i][j]表示猜[i,j]区间内的数字的时候,为了保证赢需要付出的最小代价,那么显然状态转移方程为:dp[i][j] = min(k + max(dp[i][k - 1], dp[k + 1][j])),其中i <= k <= j。下面是两种思路的具体实现,真的是大同小异,代码也容易理解。对于本题目而言,似乎动态规划的效率更高。

代码

1、带记忆的深度优先搜索(DFS + memorization):

class Solution {public:    int getMoneyAmount(int n) {        if(n == 0) {            return 0;        }        vector<vector<int>> dp(n + 1, vector<int>(n + 1, 0));        return dfs(dp, 1, n);    }private:    int dfs(vector<vector<int>>&dp, int left, int right) {        if(left >= right) {            return 0;        }        if(dp[left][right]) {           // already recorded            return dp[left][right];        }        int ans = INT_MAX, pay = 0;        for(int i = left; i <= right; ++i) {            pay = i + max(dfs(dp, left, i - 1), dfs(dp, i + 1, right));     // the amount I have to pay when I guess i            ans = min(ans, pay);        }        dp[left][right] = ans;        return ans;    }};

2、动态规划(Dynamic Programming):

class Solution {public:    int getMoneyAmount(int n) {        if(n == 0) {            return 0;         }        vector<vector<int>> dp(n + 1, vector<int>(n + 1, 0));          for(int i = n - 1; i > 0; --i) {              for(int j = i + 1; j <= n; ++j) {                  int ans = INT_MAX, pay = 0;                for(int k = i; k < j; ++k) {                    pay = k + max(dp[i][k - 1], dp[k + 1][j]);                    ans = min(ans, pay);                  }                dp[i][j] = ans;              }          }          return dp[1][n];    }};

阅读全文
0 0
原创粉丝点击