464. Can I Win
https://leetcode.com/problems/can-i-win/description/
In the "100 game," two players take turns adding, to a running total, any integer from 1..10. The player who first causes the running total to reach or exceed 100 wins.
What if we change the game so that players cannot re-use integers?
For example, two players might take turns drawing from a common pool of numbers of 1..15 without replacement until they reach a total >= 100.
Given an integer maxChoosableInteger and another integer desiredTotal, determine if the first player to move can force a win, assuming both players play optimally.
You can always assume that maxChoosableInteger will not be larger than 20 and desiredTotal will not be larger than 300.
Example
Input:
maxChoosableInteger = 10
desiredTotal = 11 Output:
false Explanation:
No matter which integer the first player choose, the first player will lose.
The first player can choose an integer from 1 up to 10.
If the first player choose 1, the second player can only choose integers from 2 up to 10.
The second player will win by choosing 10 and get a total = 11, which is >= desiredTotal.
Same with other integers chosen by the first player, the second player will always win.
Sol:
After solving several "Game Playing" questions in leetcode, I find them to be pretty similar. Most of them can be solved using the top-down DP approach, which "brute-forcely" simulates every possible state of the game.
The key part for the top-down dp strategy is that we need to avoid repeatedly solving sub-problems. Instead, we should use some strategy to "remember" the outcome of sub-problems. Then when we see them again, we instantly know their result. By doing this, we can always reduce time complexity from exponential to polynomial.
(EDIT: Thanks for @billbirdh for pointing out the mistake here. For this problem, by applying the memo, we at most compute for every subproblem once, and there areO(2^n)subproblems, so the complexity isO(2^n)after memorization. (Without memo, time complexity should be likeO(n!))For this question, the key part is:
what is the state of the game? Intuitively, to uniquely determine the result of any state, we need to know:
- The unchosen numbers
- The remaining desiredTotal to reach
A second thought reveals that 1) and 2) are actually related because we can always get the 2) by deducting the sum of chosen numbers from original desiredTotal.
Then the problem becomes how to describe the state using 1).
In my solution, I use a boolean array to denote which numbers have been chosen, and then a question comes to mind, if we want to use a Hashmap to remember the outcome of sub-problems, can we just use
Map<boolean[], Boolean>? Obviously we cannot, because the if we use boolean[] as a key, the reference to boolean[] won't reveal the actual content in boolean[].Since in the problem statement, it says
maxChoosableIntegerwill not be larger than20, which means the length of our boolean[] arraywill be less than20. Then we can use anIntegerto represent this boolean[] array. How?Say the boolean[] is
{false, false, true, true, false}, then we can transfer it to an Integer with binary representation as00110. Since Integer is a perfect choice to be the key of HashMap, then we now can "memorize" the sub-problems usingMap<Integer, Boolean>.The rest part of the solution is just simulating the game process using the top-down dp.
class Solution {
Map<Integer, Boolean> map;
boolean[] used;
public boolean canIWin(int maxChoosableInteger, int desiredTotal) {
// Brute force. Game playing problems are all about brute force basically...
int sum = (1+maxChoosableInteger) * maxChoosableInteger/2;
if (sum < desiredTotal) return false;
if (desiredTotal <= 0) return true;
map = new HashMap();
used = new boolean[maxChoosableInteger+1];
return helper(desiredTotal);
}
public boolean helper(int desiredTotal){
if(desiredTotal <= 0) return false;
int key = format(used);
if (!map.containsKey(key)){
// try every unchosen number as next step
for (int i = 1; i < used.length; i++){
if(!used[i]){
used[i] = true;
// check if this leads to a win (i.e. the other player lose)
if (!helper(desiredTotal - i)){
map.put(key, true);
used[i] = false;
return true;
}
used[i] = false;
}
}
map.put(key, false);
}
return map.get(key);
}
// transfer boolean[] to an Integer
public int format(boolean[] used){
int num = 0;
for(boolean b: used){
// i would never think of using bit manipulation on this....
num <<= 1;
if(b) num |= 1;
}
return num;
}
}
464. Can I Win的更多相关文章
- 状态压缩 - LeetCode #464 Can I Win
动态规划是一种top-down求解模式,关键在于分解和求解子问题,然后根据子问题的解不断向上递推,得出最终解 因此dp涉及到保存每个计算过的子问题的解,这样当遇到同样的子问题时就不用继续向下求解而直接 ...
- [LeetCode] 464. Can I Win 我能赢吗
In the "100 game," two players take turns adding, to a running total, any integer from 1.. ...
- 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 All in One 题目讲解汇总(持续更新中...)
终于将LeetCode的免费题刷完了,真是漫长的第一遍啊,估计很多题都忘的差不多了,这次开个题目汇总贴,并附上每道题目的解题连接,方便之后查阅吧~ 477 Total Hamming Distance ...
- leetcode bugfree note
463. Island Perimeterhttps://leetcode.com/problems/island-perimeter/就是逐一遍历所有的cell,用分离的cell总的的边数减去重叠的 ...
- LeetCode All in One题解汇总(持续更新中...)
突然很想刷刷题,LeetCode是一个不错的选择,忽略了输入输出,更好的突出了算法,省去了不少时间. dalao们发现了任何错误,或是代码无法通过,或是有更好的解法,或是有任何疑问和建议的话,可以在对 ...
- All LeetCode Questions List 题目汇总
All LeetCode Questions List(Part of Answers, still updating) 题目汇总及部分答案(持续更新中) Leetcode problems clas ...
随机推荐
- java线程池的实现机制
原文链接:http://www.studyshare.cn/blog-front/blog/details/1133 一.java中提供的线程在开发中可能并不会直接使用,多线程编程场景使用java的线 ...
- TinkPHP框架学习-01基本知识
1-----目录结构 2-----访问地址 3-----MVC开发 一 目录结构 |--Application 程序文件夹 |--Common 公共方法函数 |--Home 模块 |也可以自 ...
- MM-物料分类帐差异分摊
物料分类帐差异分摊-MR21-MR22: https://wenku.baidu.com/view/6599e8f326fff705cc170ad8.html
- activiti-6.0工作流应用模板
acriviti6.0官方操作指南:https://www.activiti.org/userguide/#demo.setup.one.minute.version 下载 acriviti6.0压 ...
- Docker镜像操作命令
一.使用Docker镜像 1. 获取镜像 可以使用docker pull命令直接从Docker Hub镜像源来下载镜像.该命令的格式为docker pull NAME[:TAG].其中,NAME是镜像 ...
- 2019/4/17 Linux学习
一.Linux的文件系统 其中/prov./srv./sys 文件为文件系统,技术不过硬不要去修改:二.关于Xshell.Xft1.服务器的端口可有65535个可设置,开的越多安全性越差:2.远程登录 ...
- linux dns域名缓存
在linux服务器中,我们 总会设置一个dns做域名解析 一般来说dns的缓存是不会造成多大的困扰,但是,有时候会遇到dns解析导致网络不能正常访问 在linux中,有一个缓存服务,我们可以重启这个来 ...
- LinkedHashMap 根据PUT顺序排序Map
最近工程里面报表需要合计 , 因为所有的项都是动态的,所以只能动态添加. 思路是使用Map,初始化所有Map,然后在Map中合计并且覆盖. 使用HashMap , 初始化后所有动态项的顺序都乱了. M ...
- iframe登录超时跳转登录页面
1.可以在登录页面加jQuery验证 $(function () { //判断一下当前是不是做顶层,如果不是,则做一下顶层页面重定向 if (window != top) { top.location ...
- django xadmin后台页面实现二级联动
思路 先找到控件id ,这样就可以监听change事件 然后把自己写的js加入xadmin中 添加url和view,接受ajax请求和发送数据 第一步:找到联动上下级的ID 在浏览器中通过F12查看 ...