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.

Idea 1. DFS with memory.

Understanding the question is not easy, starting from small example,

maxChoosableInteger = 2, desiredTotoal = 3, first player lose, depends on who play the last, 2%2 = 0 means the 2nd player pick the last number

maxChoosableInteger = 2, desiredTotal = 4, first player lose no matter what number choose (or say both player will lose, as no one can reach the state to make the sum of choose numbers so far by both player  >= desiredTotal)

maxChoosableInteger = 2, desiredTotal = 2, if first player win if picking 2, otherwise lose

maxChoosableInteger = 3, desiredTotal = 5,

  a. if 1st player choose 1, the state for second state is [2, 3], desiredTotoal = 4; if 2nd player choose 2, 1st player has state [3], desiredTotoal = 2, 1st player win; if 2nd player choose 3, 1st has tate [2], desiredTotal = 1, 1st player win; it mean no matter what 2nd palyer choose, with given state [2, 3], desiredTotal = 4, the 2nd player will lose, actually any player with such state will lose. As long as the 1st player can make a move and cause the state to be such losing state, the 1st player can win, or in any state which can make the next player lose, the current player can win.

b. if 1st player choose 2, the state is [1, 3], desiredTotal = 3; if 2nd player choose 3, the 2nd player win

c. if 1st player coose 3, the state is [1, 2], desiredTotal = 2; if the 2nd player choose 2, the 2nd player win.

Assume maxChoosableInteger = N for easy notation, result lose = false, win = true, considering the corner cases:

1. false if sum(1...N) = (1+N)*N/2 < desiredTotal

2. (N%2 == 1) if sum(1..N) == desiredTotal, depending who takes the last number

The core idea is to store the state and the result to save recomputation. If just bruteforce backtracking, the first player has N choices, the 2nd player has N-1 choices on the next level, there are N*(N-1)*(N-2)...1 = O(N!) nodes on searching tree,  since subproblems could get computed more than once, to avod recomputation on the same subproblem, a common technique is to use cache to store the state and result.  Since there are O(2^N) state, for each number can be picked or not, each subproblem takes O(N) time to loop the allowed number,

Time complexity: O(N2^N)

Space complexity: O(2^N)

How do we define the state of the game? Initially the list of allowed numbers + updated desired total, since the remaining total = desiredTotal - sum(not allowed number), the allowed numbers is enough to infer the remaining toal. How to represent the state?

1. arrays of integers [1...N] or arrays of boolean [true, true...]

2. integer, since N will not be larger than 20, we could use bit mask to represent the state by a number, for N = 2, 3(0b011) means 1 and 2 has been choosen. The advantage is that using integer do not need to reset the state after backtracking, as it's pass by value.

initial idea, arrays of integers + updated desired total for state, also the removing choosing elements from array is not a good idea, which is involved copying new array and inserting the element back to the original state to keep the order.

Note: we need to reset the state even it's winning, because we don't know which player is winning, we might need to continue searching, hence we need to reset the previous state before the current move.

 class Solution {
private boolean canIWinHelper(int desiredTotal, List<Integer> candidates, Map<String, Boolean> gameCache) {
String key = desiredTotal + ":" + candidates;
if(gameCache.containsKey(key)) {
return gameCache.get(key);
}
else {
boolean result = false; List<Integer> copy = new ArrayList<>(candidates);
for(int i= 0; i < copy.size(); ++i) {
int num = candidates.remove(i);
if(num >= desiredTotal || !canIWinHelper(desiredTotal - num, candidates, gameCache)) {
result = true;
candidates.add(i, num);
break;
} candidates.add(i, num);
} gameCache.put(key, result);
return result;
}
} public boolean canIWin(int maxChoosableInteger, int desiredTotal) {
List<Integer> candidates = new ArrayList<>();
int sum = 0;
for(int i = 1; i <= maxChoosableInteger; ++i) {
sum += i;
candidates.add(i);
} if(desiredTotal > sum) {
return false;
} Map<String, Boolean> gameCache = new HashMap<>(); return canIWinHelper(desiredTotal, candidates, gameCache);
}
}

arrays of booleans with corner cases:

 class Solution {
private boolean canIWinHelper(int desiredTotal, boolean[] state, Map<String, Boolean> gameCache) {
String key = Arrays.toString(state);
if(gameCache.containsKey(key)) {
return gameCache.get(key);
} boolean result = false;
for(int i = 1; i <= state.length-1; ++i) {
if(!state[i]) {
state[i] = true;
if(i >= desiredTotal || !canIWinHelper(desiredTotal - i, state, gameCache)) {
result = true;
state[i] = false;
break;
}
state[i] = false;
}
}
gameCache.put(key, result); return result;
} public boolean canIWin(int maxChoosableInteger, int desiredTotal) {
int sum = maxChoosableInteger * (1 + maxChoosableInteger);
if(sum < desiredTotal) {
return false;
}
if(sum == desiredTotal) {
return (maxChoosableInteger%2 == 1);
} boolean[] state = new boolean[maxChoosableInteger + 1]; Map<String, Boolean> gameCache = new HashMap<>(); return canIWinHelper(desiredTotal, state, gameCache);
}
}

integer as state, using bit operation

 class Solution {
private boolean canIWinHelper(int maxChoosableInteger, int desiredTotal, int state, Map<Integer, Boolean> gameCache) { if(gameCache.containsKey(state)) {
return gameCache.get(state);
} boolean result = false;
for(int i = 1; i <= maxChoosableInteger; ++i) {
int allowed = (state >> i) & 1;
if(allowed == 0) {
if(i >= desiredTotal || !canIWinHelper(maxChoosableInteger, desiredTotal - i, state^(1 << i), gameCache)) {
result = true;
break;
}
}
}
gameCache.put(state, result); return result;
} public boolean canIWin(int maxChoosableInteger, int desiredTotal) {
int sum = maxChoosableInteger * (1 + maxChoosableInteger);
if(sum < desiredTotal) {
return false;
}
if(sum == desiredTotal) {
return (maxChoosableInteger%2 == 1);
} Map<Integer, Boolean> gameCache = new HashMap<>();
int state = 0; return canIWinHelper(maxChoosableInteger, desiredTotal, state, gameCache);
}
}

python much conciser code even using integer array

 class Solution:
def canIWinHelper(self, candidates, desiredTotal, gameCache) -> bool:
key = str(candidates) if key in gameCache:
return gameCache[key] for i in range(len(candidates)):
if candidates[i] >= desiredTotal or not self.canIWinHelper(list(candidates[:i]) + list(candidates[i+1:]), desiredTotal - candidates[i], gameCache):
gameCache[key] = True
return True gameCache[key] = False
return False def canIWin(self, maxChoosableInteger: int, desiredTotal: int) -> bool:
sum = maxChoosableInteger * (1 + maxChoosableInteger) / 2
if sum < desiredTotal:
return False if sum == desiredTotal:
return (maxChoosableInteger%2 == 1) return self.canIWinHelper(range(1, maxChoosableInteger+1), desiredTotal, {})
 class Solution:
def canIWinHelper(self, maxChoosableInteger, desiredTotal, state, gameCache) -> bool:
if state in gameCache:
return gameCache[state] for i in range(maxChoosableInteger):
allowed = (state >> i) & 1
if allowed == 0:
num = i + 1
if (num >= desiredTotal) or (not self.canIWinHelper(maxChoosableInteger, desiredTotal - num, state ^ (1 << i), gameCache)):
gameCache[state] = True
return True gameCache[state] = False
return False def canIWin(self, maxChoosableInteger: int, desiredTotal: int) -> bool:
sum = maxChoosableInteger * (1 + maxChoosableInteger) / 2
if sum < desiredTotal:
return False if sum == desiredTotal:
return (maxChoosableInteger%2 == 1) return self.canIWinHelper(maxChoosableInteger, desiredTotal, 0, {})

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.

Can I win LT464的更多相关文章

  1. 【Win 10 应用开发】启动远程设备上的应用

    这个功能必须在“红石-1”(build 14393)以上的系统版中才能使用,运行在一台设备上的应用,可以通过URI来启动另一台设备上的应用.激活远程应用需要以下前提: 系统必须是build 14393 ...

  2. Win.ini和注册表的读取写入

    最近在做打包的工作,应用程序的配置信息可以放在注册表文件中,但是在以前的16位操作系统下,配置信息放在Win.ini文件中.下面介绍一下Win.ini文件的读写方法和注册表的编程. 先介绍下Win.i ...

  3. 苹果台式一体机笔记本安装win双系统攻略教程

    步骤 序:win系统下载 :http://www.itellyou.cn 选择要安装的系统进行下载,本文以win7为例   进入苹果系统,左上角——前往——实用工具——BootCamp 助理 点击继续 ...

  4. Win下最爱效率利器:AutoHotKey

    AutoHotkey是一个windows下的开源.免费.自动化软件工具.它由最初旨在提供键盘快捷键的脚本语言驱动(称为:热键),随着时间的推移演变成一个完整的脚本语言.但你不需要把它想得太深,你只需要 ...

  5. Win下必备利器之Cmder

    诚言,对于开发码字者,Mac和Linux果断要比Windows更贴心;但只要折腾下,Windows下也是有不少利器的.之前就有在Windows下效率必备软件一文中对此做了下记载:其虽没oh-my-zs ...

  6. 【Win 10 应用开发】手写识别

    记得前面(忘了是哪天写的,反正是前些天,请用力点击这里观看)老周讲了一个14393新增的控件,可以很轻松地结合InkCanvas来完成涂鸦.其实,InkCanvas除了涂鸦外,另一个大用途是墨迹识别, ...

  7. 【Win 10 应用开发】InkToolBar——涂鸦如此简单

    从WPF开始,就有个InkCanvas控件,封装了数字墨迹处理相关的功能,Silverlight到Win 8 App,再到UWP应用,都有这个控件,所以,老周说了3688遍,凡是.net基础扎实者,必 ...

  8. 【Win 10 应用开发】导入.pfx证书

    这个功能其实并不常用,一般开发较少涉及到证书,不过,简单了解一下还是有必要的. 先来说说制作测试证书的方法,这里老周讲两种方法,可以生成用于测试的.pfx文件. 产生证书,大家都知道有个makecer ...

  9. 【Win 10应用开发】延迟共享

    延迟共享是啥呢,这么说吧,就是在应用程序打开共享面板选择共享目标时,不会设置要共享的数据,而是等到共享目标请求数据时,才会发送数据,而且,延迟操作可以在后台进行. 这样说似乎过于抽象,最好的诠释方法, ...

随机推荐

  1. 数据类型&分支流程控制(2)

    1.数据类型 1.数据类型 局部变量:书写在方法中的变量: 全局变量:书写在类中,与方法平级的变量: -如果没有给变量赋初值 -全局变量会默认拥有一个初始值 -局部变量将没有初始值,这个时候不能使用这 ...

  2. selenium ide界面介绍

    Selenium Ide是firefox浏览器的一个插件,可以进行web的录制和回放,完成简单的自动化测试,同时可以将录制的脚本导出多种语言的脚本. 下面是Selenium Ide的界面: Base  ...

  3. 使用iptables禁止外网访问tomcat的8080端口

    如果项目同时使用了nginx反向代理服务器和tomcat等web服务器,并且两台服务器都暴露于公网中,那么通常我们会禁止外网直接访问tomcat,因为以下原因: 1.如果可以直接访问tomcat,那么 ...

  4. 使用FFMPEG类库分离出多媒体文件中的H.264码流

    在使用FFMPEG的类库进行编程的过程中,可以直接输出解复用之后的的视频数据码流.只需要在每次调用av_read_frame()之后将得到的视频的AVPacket存为本地文件即可. 经试验,在分离MP ...

  5. avcodec_decode_video2少帧问题

    使用libav转码视频时发现一个问题:使用下面这段代码解码视频时,解码中会不时丢掉几帧. ){ ret = avcodec_decode_video2(video_dec_ctx, vframe, & ...

  6. TOJ5398: 签到大富翁(简单模拟) and TOJ 5395: 大于中值的边界元素(数组的应用)

    Python代码!!! 5395 传送门:http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=53 ...

  7. const和volatile分析

    c语言中const修饰的变量是只读的,不能直接作为赋值号的左值,其本质还是变量:会占用内存空间:本质上const在编译器有用,运行时无用(还是可以通过指针改变它的值) ; int *p=&ab ...

  8. 转)服务器安装部署ESXI6.0

    1.制作一个ESXI6.0的系统安装盘 2.服务器启动后加载VMware ESXi 6.0的ISO文件,开始安装. 3.ESXi引导装入程序,VMware ESXi引导过程,在屏幕上方显示的版本号.内 ...

  9. 39-java中Arrays.sort 和 collections.sort()总结

    总结一下java 中的两种排序工具: Arrays.sort() : 主要针对 数组类型排序,如果数组里面的元素是对象,要按对象属性排序的话,需要重写 Comparator() 函数,重写里面的  i ...

  10. IIS 7.5 上传文件大小限制

    上传插件:uploadify IIS版本:7.5 描述: 从IIS6升级到IIS7.5以后,网站上传文件大小被限制了,在Chrome下提示:ERR_CONNECTION_RESET,网上的各种方法都试 ...