解法一:动态规划

作为先手只需要找到一种让下一个行动者必输的策略,就可以保证自己必胜。
比如现在是 N ,如果存在 N 的因子 x ,满足N-x 时先手必输,那么 N 时只要取 x 就可以保证先手必胜。反之,找不到这种方案时, N 时先手必输。

  1. import java.util.LinkedList;
  2. import java.util.List;
  3. class Solution {
  4. public boolean divisorGame(int N) {
  5. // dp[i]表示数字为i时先手能否保证赢得比赛
  6. boolean[] dp = new boolean[N + 1];
  7. dp[1] = false;
  8. for (int i = 2; i <= N; ++i) {
  9. dp[i] = false;
  10. // 只要找到一种必胜策略即可
  11. for (int j : getFactors(i)) {
  12. // 用i-j替换i可以保证下一个先手必输
  13. // 那么说明本次操作方有必胜策略
  14. if (!dp[i - j]) {
  15. dp[i] = true;
  16. break;
  17. }
  18. }
  19. }
  20. return dp[N];
  21. }
  22. /**
  23. * 获取n的所有因子, 不包括n本身
  24. *
  25. * @param n
  26. * @return n的所有因子, 不包括n
  27. */
  28. private List<Integer> getFactors(int n) {
  29. List<Integer> ans = new LinkedList<Integer>();
  30. ans.add(1);
  31. for (int i = 2; i <= Math.sqrt(n); ++i) {
  32. if (n % i == 0) {
  33. ans.add(i);
  34. if (i * i != n) {
  35. ans.add(n / i);
  36. }
  37. }
  38. }
  39. return ans;
  40. }
  41. }

解法二:规律

其实根据解法一的思路,可以找到规律。首先关注以下性质。

  • 1是所有数的因子,必有 N-1 这种方案
  • 奇数的所有因子都是奇数,因此当 N 为奇数时, N-x 均为偶数

dp[1]=falsedp[2]=true ,以这两个为基础,可以通过数学归纳法推断出:当N为偶数时, dp[N-1]=false ,因此 dp[N]=true ;当N为奇数时, dp[N-x] 恒为 true ,因此 dp[N]=false

  1. class Solution {
  2. public boolean divisorGame(int N) {
  3. return (N % 2 == 0);
  4. }
  5. }