解法一:动态规划
作为先手只需要找到一种让下一个行动者必输的策略,就可以保证自己必胜。
比如现在是 N
,如果存在 N
的因子 x
,满足N-x
时先手必输,那么 N
时只要取 x
就可以保证先手必胜。反之,找不到这种方案时, N
时先手必输。
import java.util.LinkedList;
import java.util.List;
class Solution {
public boolean divisorGame(int N) {
// dp[i]表示数字为i时先手能否保证赢得比赛
boolean[] dp = new boolean[N + 1];
dp[1] = false;
for (int i = 2; i <= N; ++i) {
dp[i] = false;
// 只要找到一种必胜策略即可
for (int j : getFactors(i)) {
// 用i-j替换i可以保证下一个先手必输
// 那么说明本次操作方有必胜策略
if (!dp[i - j]) {
dp[i] = true;
break;
}
}
}
return dp[N];
}
/**
* 获取n的所有因子, 不包括n本身
*
* @param n
* @return n的所有因子, 不包括n
*/
private List<Integer> getFactors(int n) {
List<Integer> ans = new LinkedList<Integer>();
ans.add(1);
for (int i = 2; i <= Math.sqrt(n); ++i) {
if (n % i == 0) {
ans.add(i);
if (i * i != n) {
ans.add(n / i);
}
}
}
return ans;
}
}
解法二:规律
其实根据解法一的思路,可以找到规律。首先关注以下性质。
- 1是所有数的因子,必有
N-1
这种方案 - 奇数的所有因子都是奇数,因此当
N
为奇数时,N-x
均为偶数
dp[1]=false
, dp[2]=true
,以这两个为基础,可以通过数学归纳法推断出:当N为偶数时, dp[N-1]=false
,因此 dp[N]=true
;当N为奇数时, dp[N-x]
恒为 true
,因此 dp[N]=false
。
class Solution {
public boolean divisorGame(int N) {
return (N % 2 == 0);
}
}