zoukankan      html  css  js  c++  java
  • [LeetCode] 1025. Divisor Game 除数游戏


    Alice and Bob take turns playing a game, with Alice starting first.

    Initially, there is a number N on the chalkboard.  On each player's turn, that player makes a move consisting of:

    • Choosing any x with 0 < x < N and N % x == 0.
    • Replacing the number N on the chalkboard with N - x.

    Also, if a player cannot make a move, they lose the game.

    Return True if and only if Alice wins the game, assuming both players play optimally.

    Example 1:

    Input: 2
    Output: true
    Explanation: Alice chooses 1, and Bob has no more moves.
    

    Example 2:

    Input: 3
    Output: false
    Explanation: Alice chooses 1, Bob chooses 1, and Alice has no more moves.
    

    Note:

    1. 1 <= N <= 1000

    这道题说是爱丽丝和鲍勃在玩一个除数游戏,这爱丽丝和鲍勃估计就相当于我们的小明和小红,或者是李雷和韩梅梅之类的吧,经常出现啊。说是最初有一个数字N,每次每个人选一个小于N且能整除N的数字x,并将N替换为 N-x,依次进行,直到某个人没法进行了,则算输了。现在给个任意的N,且爱丽丝先走,问爱丽丝能否赢得游戏。先来分析一个下得到什么数字的时候会输,答案是当N变成1的时候,此时没法找到小于N的因子了,则输掉游戏。博主看到题后的第一个反应就是用递归,因为调用递归得到的结果是对手的胜负,若递归返回 false,则说明当前选手赢了,反之则当前选手输了。但是递归的方法不幸超时了,因为有大量的重复计算在里面,我们需要缓存这些中间变量,以避免重复计算,可以使用递归加记忆数组来做,也可以使用迭代的写法,那么就变成动态规划 Dynamic Programming 了。这里的 dp 数组定义很直接,dp[i] 表示起始数字为i时爱丽丝是否会赢,大小为 N+1,更新时从2开始就行,因为0和1都是 false,从2更新到N,对于每个数字,都从1遍历到该数字,找小于该数的因子,不能整除的直接跳过,能整除的看 dp[i-j] 的值,若为 false,则 dp[i] 更新为 true,并 break 掉即可,参见代码如下:


    解法一:

    class Solution {
    public:
        bool divisorGame(int N) {
            vector<bool> dp(N + 1);
            for (int i = 2; i <= N; ++i) {
                for (int j = 1; j < i; ++j) {
                    if (i % j != 0) continue;
                    if (!dp[i - j]) {
                        dp[i] = true;
                        break;
                    }
                }
            }
            return dp[N];
        }
    };
    

    其实这道题的终极解法就一行,直接判断奇偶即可,若N是偶数爱丽丝一定能赢,奇数一定会输。博主大概讲一下原因吧,前面提到过了,若某个人拿到了1,则表示输了,所以当拿到2的时候,一定会赢,因为取个因数1,然后把剩下的1丢给对手就赢了。对于大于2的N,最后都会先减小到2,所以其实这个游戏就是个争2的游戏。对于一个奇数N来说,小于N的因子x一定也是个奇数,则留给对手的 N-x 一定是个偶数。而对于偶数N来说,我们可以取1,然后变成一个奇数丢给对手,所以拿到偶数的人,将奇数丢给对手后,下一轮自己还会拿到偶数,这样当N不断减小后,最终一定会拿到2,所以会赢,参见代码如下:


    解法二:

    class Solution {
    public:
        bool divisorGame(int N) {
            return N % 2 == 0;
        }
    };
    

    Github 同步地址:

    https://github.com/grandyang/leetcode/issues/1025


    参考资料:

    https://leetcode.com/problems/divisor-game/

    https://leetcode.com/problems/divisor-game/discuss/274608/Simple-DP-Java-Solution

    https://leetcode.com/problems/divisor-game/discuss/296784/Come-on-in-different-explanation-from-others


    LeetCode All in One 题目讲解汇总(持续更新中...)

  • 相关阅读:
    fastjson生成和解析json数据
    fastJson API
    js实现class样式的修改、添加及删除的方法
    jquery ajax局部加载方法介绍
    jquery 动态添加和删除 ul li列表
    spring mvc3中的addFlashAttribute方法
    Spring MVC 3 : 一次上传多个文件
    pring mvc 批量上传+文件上传
    SpringMVC批量上传
    Android ADT Bundle(Eclipse with ADT) ADT R23
  • 原文地址:https://www.cnblogs.com/grandyang/p/14397707.html
Copyright © 2011-2022 走看看