LeetCode #1025 除数博弈(记一道动态规划标签下的数学题)

题目链接:

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

题目描述:

#1025 除数博弈
爱丽丝和鲍勃一起玩游戏,他们轮流行动。爱丽丝先手开局。

最初,黑板上有一个数字 N 。在每个玩家的回合,玩家需要执行以下操作:

选出任一 x,满足 0 < x < N 且 N % x == 0 。
用 N - x 替换黑板上的数字 N 。
如果玩家无法执行这些操作,就会输掉游戏。

只有在爱丽丝在游戏中取得胜利时才返回 True,否则返回 false。假设两个玩家都以最佳状态参与游戏。

示例 1:

输入:2
输出:true
解释:爱丽丝选择 1,鲍勃无法进行操作。
示例 2:

输入:3
输出:false
解释:爱丽丝选择 1,鲍勃也选择 1,然后爱丽丝无法进行操作。

提示:

1 <= N <= 1000
通过次数21,552 提交次数31,729

分析:

本来是想做做动态规划的题,在动态规划标签下面看到了这个题,结果分析了半天,动态规划做法没想出来,却用数学方式A了。

首先我们知道,拿到2的人赢,拿到1的人输

下面是几个数学知识:
奇 * 奇 = 奇,奇 * 偶 = 偶,偶 * 偶 = 偶,
奇 - 奇 = 偶,偶 - 偶 = 偶,偶 - 奇 = 奇

我们可以发现,一个奇数的约数一定是奇数,偶数的约数可能是奇数也可能是偶数。

拿到奇数的人只能选择奇数,选完了以后数就变成了偶数,因为:奇 - 奇 = 偶。

而拿到了偶数的人,可以选择奇数或者偶数,由于偶 - 偶 = 偶,偶 - 奇 = 奇,题目说了是最佳状态,所以这个人一定会拿奇数,让对手只有奇数。

故奇数先手必输。

同理,偶数先手的人必赢。 因为是最佳状态,虽然可以选择奇数和偶数,但为了让自己赢肯定会选择让对手一直拿奇数。

综上所述,奇数先手必输,偶数先手必赢。

举个例子:

N = 1,没得选,爱丽丝输
N = 2,只能选1,鲍勃没得选,爱丽丝赢
N = 3,只能选1,鲍勃也只能选1,爱丽丝没得选了,爱丽丝输
N = 4,可以是“2 1”或者“1 1 1”,爱丽丝会选能让自己赢的,即选1,还剩3,后面的只可能是“1 1”,爱丽丝赢
N = 5,只能选1,还剩4,鲍勃会选能让自己赢的,所以从“2 1”和“1 1 1”中选择了后者,即鲍勃选1,还剩3,只能是“1 1”,爱丽丝赢(3 1 1 / 1 1 1 1 1)
N = 6,爱丽丝选3或者1都必赢,她就不会选2,最终爱丽丝赢
N = 7,只能选1,还剩6,鲍勃选也肯定选让自己赢的3或者1,爱丽丝输(1 3 1 1 / 1 1 1 1 1 1)
N = 8,爱丽丝赢(1 1 3 1 1 / 1 1 1 1 1 1 1)

如果无法用数学的方式理解这个题,通过这么多的例子也可以发现规律,特别是笔试时,如果有用规律能解决的,不要怕,大胆猜,没准就能通过个60%的测试用例呢,拿几分也不亏啊。

代码:

没什么好看的…就是判断 N 的奇偶,然后奇数返回false,偶数返回true。

/*
*每个人都是最佳状态,都会走能让自己赢的一步
*发现规律:逢偶必赢,逢奇必输
*如何判断奇偶:偶数 & 1 = 0;奇数 & 1 = 1
*/
class Solution {
    public boolean divisorGame(int N) {
        return (N & 1) == 0;
    }
}                                                                                           

LeetCode #1025 除数博弈(记一道动态规划标签下的数学题)_第1张图片
这个提交结果再次印证了之前的说法,那就是LeetCode的内存消耗是包含测试用例的,本题我们没有开辟任何的空间,但是依然用了36.3MB,再就是超过10%的用户可能只算了比我们提交的用的多的人,和我们用的一样的没算上,也就是说 >36.3MB 的有 10% 的用户,剩下的 90% 大多都是 ≈36MB 的。

你可能感兴趣的:(LeetCode)