想了解更多数据结构以及算法题,可以关注微信公众号“数据结构和算法”,每天一题为你精彩解答。也可以扫描下面的二维码关注

我们正在玩一个猜数游戏,游戏规则如下:

我从 1 到 n 之间选择一个数字,你来猜我选了哪个数字。

每次你猜错了,我都会告诉你,我选的数字比你的大了或者小了。

然而,当你猜了数字 x 并且猜错了的时候,你需要支付金额为 x 的现金。直到你猜到我选的数字,你才算赢得了这个游戏。

示例:

n = 10, 我选择了8. 第一轮: 你猜我选择的数字是5,我会告诉你,我的数字更大一些,然后你需要支付5块。

第二轮: 你猜是7,我告诉你,我的数字更大一些,你支付7块。

第三轮: 你猜是9,我告诉你,我的数字更小一些,你支付9块。

游戏结束。8 就是我选的数字。

你最终要支付 5 + 7 + 9 = 21 块钱。

给定 n ≥ 1,计算你至少需要拥有多少现金才能确保你能赢得这个游戏。

答案:

public static int getMoneyAmount(int n) {return DP(1, n);
}public static int DP(int left, int right) {if (left >= right)return 0;int res = Integer.MAX_VALUE;for (int i = left; i <= right; i++) {int tmp = i + Math.max(DP(left, i - 1), DP(i + 1, right));res = Math.min(res, tmp);}return res;
}

解析:

在数字1-n之间,假如我们选择了x,数组就会分成3个部分,[1,x-1],x,[x+1,n]。那么会有3种情况,第一种我们选中了,所以这时候花费现金最少,第二种是我们选大了,第三种是我们选小了,用函数f(m,n)表示从数字m到n中所花费的最小金额,如果选择了在范围(i,j)中保证所花费最少(i<=x<=j),我们有下面这样一个公式。money=x+max(f(i,x-1)+f(x+1,j));代码第10行我们找的是最大值,因为题目说了至少花费多钱现金才能赢得游戏,我们只需要找到所有的花费最大值中的最小值即可。但是上面代码效率明显不是很高,因为递归的原因会出现重复计算,我们只需要用一个临时数组存储每次计算的结果,防止重复计算即可,我们来优化一下

public static int getMoneyAmount(int n) {int[][] table = new int[n + 1][n + 1];return DP(table, 1, n);
}public static int DP(int[][] table, int left, int right) {if (left >= right)return 0;if (table[left][right] != 0)return table[left][right];int res = Integer.MAX_VALUE;for (int i = left; i <= right; i++) {int tmp = i + Math.max(DP(table, left, i - 1), DP(table, i + 1, right));res = Math.min(res, tmp);}table[left][right] = res;return res;
}

除了递归的写法以外,我们还可以使用动态规划的方式解决,先看一下代码

public int getMoneyAmount(int n) {int[][] table = new int[n + 1][n + 1];for (int i = 2; i <= n; i++) {for (int j = i - 1; j > 0; j--) {int globalMin = Integer.MAX_VALUE;for (int k = j + 1; k < i; k++) {int localMax = k + Math.max(table[j][k - 1], table[k + 1][i]);globalMin = Math.min(globalMin, localMax);}table[j][i] = j + 1 == i ? j : globalMin;}}return table[1][n];
}

前两个for循环会组成一个封闭的空间[j,i],然后第3个for循环再从这个封闭的空间中找出所有花费最大值的最小值即可,这个最小值也只不过是在区间[j,i]之间的,然后通过外面两层的for循环最终会找出区间[1,n]的值。第10行表示如果j和i仅仅相差1的话,那么第3个for循环根本就不会执行,我们要猜最小的才能花费最少,所以选择j。下面来画个图加深一下理解

这里我们来举个例子简单说下,比如n等于5,为什么只需要6块钱就一定能赢得游戏,结合上面的分析,我们知道当我们先猜2,或者4的时候结果都是6,我们以先猜2来分析一下,

1, 如果选择的是1,我们猜2,说明大了,下一步直接猜1就行了,所以只花了2块钱。

2, 如果选择的是2,我们猜2,说明猜对了,一分没花。

3, 如果选择的是3,我们猜2,说明猜小了,下一步猜4,说明大了,在下一步直接猜3,猜对了,所以总共花了2+4=6块钱。

4, 如果选择的是4,我们猜2,说明猜小了,下一步猜4,猜中了,只花了2块钱。

5, 如果选择的是5,我们猜2,说明猜小了,下一步猜4,又小了,在下一步直接猜5,猜对了,所以总共花了2+4=6块钱。

综上所述,当n等于5的时候,我们只需要6块钱就一定能赢,

思考:

这题我估计很多人都听说过,或者看过类似的这种题,很多时候我们猜这样的题都喜欢从中间来猜,显然通过上面的分析,如果我们从中间猜不一定会有最优的结果,比如当n=5的时候,当我们选择4,或者5的时候,如果我们从中间来猜,先猜3,小了,再猜4,这时候无论是猜对了还是猜小了,所花费的肯定是大于6的,很明显不是最优解。

347,猜数字大小 II相关推荐

  1. 375. 猜数字大小 II

    375. 猜数字大小 II 我们正在玩一个猜数游戏,游戏规则如下: 我从 1 到 n 之间选择一个数字. 你来猜我选了哪个数字. 如果你猜到正确的数字,就会 赢得游戏 . 如果你猜错了,那么我会告诉你 ...

  2. ​LeetCode刷题实战375:猜数字大小 II

    算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试.所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 ! 今天和大家 ...

  3. Java实现 LeetCode 374 猜数字大小 II

    375. 猜数字大小 II 我们正在玩一个猜数游戏,游戏规则如下: 我从 1 到 n 之间选择一个数字,你来猜我选了哪个数字. 每次你猜错了,我都会告诉你,我选的数字比你的大了或者小了. 然而,当你猜 ...

  4. leetcode - 375. 猜数字大小 II

    解题思路:这道题目的意思是我告诉你一个n值,然后我会在1到n之间选一个数字,让你来猜我选了哪个数. 我们需要意识到我们在范围 (1, n)中猜数字的时候,需要考虑最坏情况下的代价.也就是说要算每次都猜 ...

  5. Leetcode 375. 猜数字大小 II 解题思路及C++实现

    方法一:递归 解题思路: 设置一个dp数组,dp[i][j] 表示从数字 i 到 j ,保证猜中所选数字所需的最小花费. 在数字 i 到 j 之间进行猜测时,我们选择数字 i < k < ...

  6. C++题解-Leecode 375. 猜数字大小 II——Leecode每日一题系列

    今天是坚持每日一题打卡的第十七天 题目链接:https://leetcode-cn.com/problems/guess-number-higher-or-lower-ii/submissions/ ...

  7. LeetCode 375. 猜数字大小 II

    题目大意: https://leetcode-cn.com/problems/guess-number-higher-or-lower-ii 我们正在玩一个猜数游戏,游戏规则如下: 我从 1 到 n ...

  8. LeetCode 375. 猜数字大小 II(DP)

    文章目录 1. 题目 2. 解题 1. 题目 我们正在玩一个猜数游戏,游戏规则如下: 我从 1 到 n 之间选择一个数字,你来猜我选了哪个数字. 每次你猜错了,我都会告诉你,我选的数字比你的大了或者小 ...

  9. leetcode算法题--猜数字大小 II★★

    原题链接:https://leetcode-cn.com/problems/guess-number-higher-or-lower-ii/ 这题难点在于不能直接使用二分法,举个例子:如果n=5,则1 ...

  10. leetcode 375. Guess Number Higher or Lower II | 375. 猜数字大小 II(动态规划思路总结)

    题目 https://leetcode.com/problems/guess-number-higher-or-lower-ii/ 题解 首先,看了 Related Topics,知道这是个 dp 问 ...

最新文章

  1. String创建对象的个数 StringBuffer
  2. 芯片焊接和PCB设计引脚的长度及位置对于焊接质量的教训
  3. 静态工厂方法之服务提供者框架
  4. 我的世界java版游戏崩溃_我的世界:MC不一样的冷知识,游戏崩溃?没想到你是这样的F3!...
  5. 交换机组网常见九大故障问题
  6. c#解决在数据表格中无法显示秒数问题
  7. c# 修饰词public, protected, private,internal的区别
  8. imu 里程计融合_MSCKF那些事(十一)算法改进4:融合直接观测
  9. java做万年历,Java做的万年历
  10. linux resin目录,Linux下resin的安装以及配置:
  11. cruzer php sandisk 闪迪u盘量产工具_闪迪u3量产工具下载 SanDisk Cruzer Micro(闪迪u盘量产工具) V1.0 官方免费版(附使用说明) 下载-脚本之家...
  12. 阿里云部署.NET后端
  13. 空气质量指数月统计历史数据爬取
  14. lnkscape制作logo
  15. 微信公众号网页授权登陆
  16. 学习强国-为中华崛起而学习
  17. 【转】使用 HTML5 设计辅助功能
  18. 跳表是个好东西你值得拥有!
  19. mysqld_multi配置
  20. 4款黑科技级别的宝藏APP,能够轻松满足你的多种需求,请低调收藏

热门文章

  1. python语言程序设计教程赵璐 第三章 课后习题 程序流程控制
  2. 滤波器原理及其作用计算机网络,电源滤波器的工作原理及作用
  3. Python实现决策树2(CART分类树及CART回归树)
  4. 计算机里的游戏怎么输入,如何输入对号(对号怎么打?电脑上和手机分别怎么打?)...
  5. RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.0 版新增消息管理
  6. excel图表上x轴y轴怎么设置的教程介绍
  7. 基站位置查询系统_Android获取手机基站位置并进行基站定位的原理
  8. C语言递归解兔子繁衍问题
  9. C++ primer 个人学习总结
  10. deepfake 图片_找到那张假照片!对抗Deepfake之路