464. Can I Win
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.
本题难度挺高的,用的是动态规划方法解决,动态规划是原问题可以分解为若干规模较小的子问题,并且具有重叠子问题和最优子结构的性质。首先要思考状态方程,状态方程是desiredTotal-i,比较不容易看出来
为了避免重叠子问题,用了hashmap来存储返回true,false的子问题的值,这里面有一个比较奇妙的地方是,将布尔类型的used数组转换成一个integer。然后把这个integer存储在hashmap里面,代码如下:
1 public class Solution { 2 public boolean canIWin(int maxChoosableInteger, int desiredTotal) { 3 Map<Integer,Boolean> map = new HashMap<>(); 4 boolean[] used = new boolean[maxChoosableInteger+1]; 5 int sum = (1+maxChoosableInteger)*maxChoosableInteger/2; 6 if(sum<desiredTotal) return false; 7 if(desiredTotal<=0) return true; 8 return helper(map,used,desiredTotal); 9 } 10 public boolean helper(Map<Integer,Boolean> map,boolean[] used,int desiredTotal){ 11 if(desiredTotal<=0) return false; 12 int key = format(used); 13 if(!map.containsKey(key)){ 14 for(int i=1;i<used.length;i++){ 15 if(!used[i]){ 16 used[i] = true; 17 if(!helper(map,used,desiredTotal-i)){ 18 used[i] = false; 19 map.put(key,true); 20 return true; 21 } 22 used[i] = false; 23 } 24 } 25 map.put(key,false); 26 } 27 return map.get(key); 28 } 29 public int format(boolean[] used){ 30 int num = 0; 31 for(int i=0;i<used.length;i++){ 32 num<<=1; 33 if(used[i]) num|=1; 34 } 35 return num; 36 } 37 }