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 are O(2^n) subproblems, so the complexity is O(2^n) after memorization. (Without memo, time complexity should be like O(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:

  1. The unchosen numbers
  2. 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 maxChoosableInteger will not be larger than 20, which means the length of our boolean[] arraywill be less than 20. Then we can use an Integer to 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 as 00110. Since Integer is a perfect choice to be the key of HashMap, then we now can "memorize" the sub-problems using Map<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的更多相关文章

  1. 状态压缩 - LeetCode #464 Can I Win

    动态规划是一种top-down求解模式,关键在于分解和求解子问题,然后根据子问题的解不断向上递推,得出最终解 因此dp涉及到保存每个计算过的子问题的解,这样当遇到同样的子问题时就不用继续向下求解而直接 ...

  2. [LeetCode] 464. Can I Win 我能赢吗

    In the "100 game," two players take turns adding, to a running total, any integer from 1.. ...

  3. LeetCode 464. Can I Win

    In the "100 game," two players take turns adding, to a running total, any integer from 1.. ...

  4. 464 Can I Win 我能赢吗

    详见:https://leetcode.com/problems/can-i-win/description/ C++: class Solution { public: bool canIWin(i ...

  5. [leetcode] 464. Can I Win (Medium)

    原题链接 两个人依次从1~maxNum中选取数字(不可重复选取同一个),累和.当一方选取数字累和后结果大于等于给定的目标数字,则此人胜利. 题目给一个maxNum和targetNum,要求判断先手能否 ...

  6. LeetCode All in One 题目讲解汇总(持续更新中...)

    终于将LeetCode的免费题刷完了,真是漫长的第一遍啊,估计很多题都忘的差不多了,这次开个题目汇总贴,并附上每道题目的解题连接,方便之后查阅吧~ 477 Total Hamming Distance ...

  7. leetcode bugfree note

    463. Island Perimeterhttps://leetcode.com/problems/island-perimeter/就是逐一遍历所有的cell,用分离的cell总的的边数减去重叠的 ...

  8. LeetCode All in One题解汇总(持续更新中...)

    突然很想刷刷题,LeetCode是一个不错的选择,忽略了输入输出,更好的突出了算法,省去了不少时间. dalao们发现了任何错误,或是代码无法通过,或是有更好的解法,或是有任何疑问和建议的话,可以在对 ...

  9. All LeetCode Questions List 题目汇总

    All LeetCode Questions List(Part of Answers, still updating) 题目汇总及部分答案(持续更新中) Leetcode problems clas ...

随机推荐

  1. ORM全集

    Django终端打印SQL语句 LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console' ...

  2. DEDECMS 多站用一个站图片

    function replaceurl($newurl) { $newurl=str_replace('src="/uploads/allimg/','src="xxx.com/u ...

  3. Python module ---- argparse

    argparse是python用于解析命令行参数和选项的标准模块,用于代替已经过时的optparse模块.argparse模块的作用是用于解析命令行参数,程序只需定义好它要求的参数,然后argpars ...

  4. 36_react_ui_antd

    1:最流行的开源react ui组件库 1.1:material-ui(国外) 1.2:ant-design(推荐:国内蚂蚁金服) 2.如何使用 方式一(页面引入): 在<head>标签内 ...

  5. Fiddler手机抓包设置

    前提条件:1).电脑需要安装Fiddler2).测试手机需要支持Wifi3).测试手机与电脑需要同一网络4).所测APP需支持代理 三.设置Fiddler 1.(1)电脑端打开安装好的的fiddler ...

  6. python字符串 列表 元组 字典相关操作函数总结

    1.字符串操作函数 find 在字符串中查找子串,找到首次出现的位置,返回下标,找不到返回-1 rfind 从右边查找 join 连接字符串数组 replace 用指定内容替换指定内容,可以指定次数 ...

  7. 变量新声明之let、const

    一.let 1.通过let声明变量不会变量声明提升 let a = 10; console.log( a ) 会报错 2. let a = 10; let a = 10; 会报错,(a 已被定义) 3 ...

  8. LinkedHashMap 根据PUT顺序排序Map

    最近工程里面报表需要合计 , 因为所有的项都是动态的,所以只能动态添加. 思路是使用Map,初始化所有Map,然后在Map中合计并且覆盖. 使用HashMap , 初始化后所有动态项的顺序都乱了. M ...

  9. 19-05【icloud】照片备份

    icloud提供了免费的存储空间,5G,超过这个量需要单独购买空间:我用的是50G,每月6元. 如果在mac或者iphone上开启了本地的照片流,则会自动同步到icloud,同时各个设备的客户端(ip ...

  10. js获取地址栏上参数的值

    function GetQuerystring(name){ var reg=new RegExp("(^|&)" + name +"=([^&]*)(& ...