解法一:动态规划
作为先手只需要找到一种让下一个行动者必输的策略,就可以保证自己必胜。
比如现在是 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);}}
