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 ...
随机推荐
- jvm(一)类加载器
1.jvm的生命周期结束的几种情况 a.执行了System.exit()方法 b.程序正常执行结束 c.程序在执行过程中遇到了异常或错误而异常终止 d.操作系统出现错误 2.类加载过程 加载:查找并加 ...
- servlet的运行机制,转发和重定向
一.当发送一个请求到服务器端的时候,容器(tomcat)会判断该路径属于哪一个servlet进行处理,servlet有一个抽象父类“httpservlet”,这个类是一个模板设计模式的类,其中serv ...
- 回溯法 17. Letter Combinations of a Phone Number
class Solution { public: map<char,string> dict; vector<string> letterCombinations(string ...
- C#下用于同时使用OpenCvSharp和Emgu.CV两个库的相互转换库
很久以前做的一个图像处理项目,在.NET平台上使用OpenCV,但因为同时使用了C#支持的两个比较有名的库,由于封装方式不同,难免要转换两个库之间的Mat对象. 同时还封装了一些WPF下,System ...
- foreach和List.Foreach 退出循环相关问题
foreach: continue;:退出本次循环 break;:退出循环 return;:退出循环 List.Foreach: return;:退出本次循环 小结:list.Foreach中不能退出 ...
- Could not HEAD 'https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/3.2.0/gradle-3.2.0.pom'.
- 使用Fiddle抓取IOS手机
1.配置Fiddle (Tools->Options) 勾选后,按照提示下载安装一个认证 Fiddle默认8888端口 2.电脑开个热点,手机连上后,在该wifi的代理配置中,选择手动,服务器输 ...
- 【MYSQL】MYSQLの環境構築
ダウンロード:https://dev.mysql.com/downloads/mysql/ 手順① 手順② mysql.iniの設定について [mysql]default-character-set= ...
- CentOS7 安装phpMyAdmin-4.8.3-all-languages
1 需要先安装好web服务(如nginx).PHP.数据库(如MySQL) 在此略过... wget -O /tmp/phpMyAdmin--all-languages.tar.gz https:// ...
- 原型设计工具—Axure
作为软件设计的一员,需要在软件开发初期确保软件的具体内容,防止后期大幅度的修改. 在这样的情况下,原型设计软件就起到了关键的作用. 摘要: 原型设计为什么这么重要呢? 因为它帮助我们搭建了低保真或高保 ...