464. 我能赢吗 (Medium)
问题描述
在 "100 game" 这个游戏中,两名玩家轮流选择从 1 到 10 的任意整数,累计整数和,先使得累计整数和
达到或超过 100 的玩家,即为胜者。
如果我们将游戏规则改为 “玩家 不能 重复使用整数” 呢?
例如,两个玩家可以轮流从公共整数池中抽取从 1 到 15 的整数(不放回),直到累计整数和 >= 100。
给定两个整数 maxChoosableInteger (整数池中可选择的最大数)和
desiredTotal(累计和),若先出手的玩家能稳赢则返回 true ,否则返回 false
。假设两位玩家游戏时都表现 最佳 。
示例 1:
输入:maxChoosableInteger = 10, desiredTotal = 11
输出:false
解释:
无论第一个玩家选择哪个整数,他都会失败。
第一个玩家可以选择从 1 到 10 的整数。
如果第一个玩家选择 1,那么第二个玩家只能选择从 2 到 10 的整数。
第二个玩家可以通过选择整数 10(那么累积和为 11 >= desiredTotal),从而取得胜利.
同样地,第一个玩家选择任意其他整数,第二个玩家都会赢。
示例 2:
输入:maxChoosableInteger = 10, desiredTotal = 0
输出:true
示例 3:
输入:maxChoosableInteger = 10, desiredTotal = 1
输出:true
提示:
1 <= maxChoosableInteger <= 200 <= desiredTotal <= 300
解题思路
dfs
首先从递归的角度来思考,(事实上这里博弈的角度并没有那么强),第一个玩家选了x,那么对下一个玩家而言,他的desiredTotal就变成了desiredTotal - x,而如果下一个玩家赢了,那么第一个玩家就输了。
状态压缩 + 记忆化搜索
首先注意到,这个题中maxChoosableInteger <= 20,因此我们可以用一个最长不超过20位的二进制数mask来表示数的选择过程,如果mask的第i位为1,说明i还没有被选择过,即还能选;
同时我们可以注意到,desired_total的值直接由mask来决定,因为mask的初始值为2^n - 1,所以写cache数组的时候无需加上desired_total的维度;
注意位运算的优先级是很低的,建议加括号。
代码
class Solution {
public:
// 改写成位运算的形式
bool dfs(int desired_total, int cur_total, int bit20, int max_int, unordered_map<int, int> &ump) {
if (desired_total <= 0) {
return false;
}
if (bit20 == 0) {
return true;
}
if (ump.find(bit20) != ump.end()) {
return ump[bit20];
}
bool tmp = false;
int cnt = 1;
for (int i = max_int - 1; i >= 0; --i) {
if ((bit20 & (1 << i)) != 0) { // 说明数i + 1还没有被选
int mask = (bit20 ^ (1 << i));
tmp = tmp || (!dfs(desired_total - i - 1, cur_total + i + 1, mask, max_int, ump));
}
if (tmp) {
ump[bit20] = true;
return ump[bit20];
}
}
ump[bit20] = false;
return ump[bit20];
}
bool canIWin(int maxChoosableInteger, int desiredTotal) {
if (desiredTotal <= maxChoosableInteger) {
return true;
}
if ((maxChoosableInteger + 1) * maxChoosableInteger / 2 < desiredTotal)
return false;
unordered_map<int, int> ump;
int bit20 = (1 << maxChoosableInteger) - 1;
return dfs(desiredTotal, 0, bit20, maxChoosableInteger, ump);
}
};
464. 我能赢吗 (Medium)的更多相关文章
- Leetcode 464.我能赢吗
我能赢吗 在 "100 game" 这个游戏中,两名玩家轮流选择从 1 到 10 的任意整数,累计整数和,先使得累计整数和达到 100 的玩家,即为胜者. 如果我们将游戏规则改为 ...
- Swift LeetCode 目录 | Catalog
请点击页面左上角 -> Fork me on Github 或直接访问本项目Github地址:LeetCode Solution by Swift 说明:题目中含有$符号则为付费题目. 如 ...
- leetcode动态规划题目总结
Hello everyone, I am a Chinese noob programmer. I have practiced questions on leetcode.com for 2 yea ...
- C#LeetCode刷题-极小化极大
极小化极大篇 # 题名 刷题 通过率 难度 375 猜数字大小 II 23.4% 中等 464 我能赢吗 25.5% 中等 486 预测赢家 40.4% 中等 843 猜猜这个单词 2 ...
- C#LeetCode刷题-动态规划
动态规划篇 # 题名 刷题 通过率 难度 5 最长回文子串 22.4% 中等 10 正则表达式匹配 18.8% 困难 32 最长有效括号 23.3% 困难 44 通配符匹配 17.7% ...
- LeetCode刷题总结-动态规划篇
本文总结LeetCode上有动态规划的算法题,推荐刷题总数为54道.具体考点分析如下图: 1.中心扩展法 题号:132. 分割回文串 II,难度困难 2.背包问题 题号:140. 单词拆分 II,难度 ...
- [LeetCode] 464. Can I Win 我能赢吗
In the "100 game," two players take turns adding, to a running total, any integer from 1.. ...
- 464 Can I Win 我能赢吗
详见:https://leetcode.com/problems/can-i-win/description/ C++: class Solution { public: bool canIWin(i ...
- [leetcode] 464. Can I Win (Medium)
原题链接 两个人依次从1~maxNum中选取数字(不可重复选取同一个),累和.当一方选取数字累和后结果大于等于给定的目标数字,则此人胜利. 题目给一个maxNum和targetNum,要求判断先手能否 ...
- [LeetCode] Can I Win 我能赢吗
In the "100 game," two players take turns adding, to a running total, any integer from 1.. ...
随机推荐
- 建立一个简单干净的 gn+ninja 工具链
背景 事情的起因是,想找个跨 Windows 和 Mac 的构建方案.第一考虑自然是 CMake,毕竟基本上是事实标准了. 但是研究了一下 Modern CMake,也就是以 target 为核心的理 ...
- [数据结构]Hash Table(哈希表)
Hash Table基本概念 散列函数:一个把查找表中的关键字映射成该关键字对应的地址的函数,记为Hash(key)=Addr. 散列函数可能会把两个或者两个以上的关键字映射到同一个地址,称这种情况为 ...
- Go读取yaml文件到struct类
1.yaml文件准备 common: secretid: AKIDxxxxx secretKey: 3xgGxxxx egion: ap-guangzhou zone: ap-guangzhou-7 ...
- 【OpenWRT】增加第三方开源库 - 二维码开源库 zbar
序言 第一次开始写博客,在日常学习和工作当中 CSDN 给我帮助很大,因此我也在 CSDN 奉献自己的经验,借此回馈 CSDN 对我的帮助,希望自己的经验可以帮助需要的人,也方便自己后续复习之用,同时 ...
- sync.Once 使用及解析
目录 前言 1. sync.Once 简介 2. sync.Once 源码解析 2.1 为什么 done 作为第一个字段 2.2 Do 方法的实现细节 2.3 其他重要细节 3. sync.Once ...
- (原创)【B4A】一步一步入门02:可视化界面设计器、控件的使用
一.前言 上篇 (原创)[B4A]一步一步入门01:简介.开发环境搭建.HelloWorld 中我们创建了默认的项目,现在我们来看一下B4A项目的构成,以及如何所见即所得的设计界面,并添加和使用自带的 ...
- Nginx09 http的keepalive及在nginx的配置使用
1 为什么要有Connection: keep-alive? 在早期的HTTP/1.0中,每次http请求都要创建一个连接,而创建连接的过程需要消耗资源和时间,为了减少资源消耗,缩短响应时间,就需要重 ...
- 断点调试/认证/权限/频率-源码分析/基于APIView编写分页/异常处理
内容概要 断点调试 认证/权限/频率-源码分析 基于APIView编写分页 异常处理 断点调试 # 程序以 debug模式运行,可以在任意位置停下,查看当前情况下变量数据的变化情况 # pycharm ...
- centos7 在线或离线安装python3
1.前言 本文会使用到yum和wget,如果两者都不能用,参考安装教程 https://www.cnblogs.com/dennisdong/p/17037248.html 2.查看是否安装wget和 ...
- JavaScript 日期和时间的格式化
一.日期和时间的格式化 1.原生方法 1.1.使用 toLocaleString 方法 Date 对象有一个 toLocaleString 方法,该方法可以根据本地时间和地区设置格式化日期时间.例如: ...