3-292. Nim Game

题目描述:

You are playing the following Nim Game with your friend: There is a heap(堆) of stones on the table, each time one of you take turns to remove 1 to 3 stones. The one who removes the last stone will be the winner. You will take the first turn to remove the stones.

Both of you are very clever and have optimal strategies for the game. Write a function to determine whether you can win the game given the number of stones in the heap.

Example:

Input: 4
Output: false 
Explanation: If there are 4 stones in the heap, then you will never win the game;
             No matter 1, 2, or 3 stones you remove, the last stone will always be 
             removed by your friend.

说明:首先谈下我个人对Nim游戏的理解。题目假定是我们先取,正如示例中展示的情形一样:如果轮到我们去取时,石碓里只剩下4颗石头,那无论我们怎么取,另外一个人总能一次就把剩下的石头全部取完,这样的话我们必输。我们以此为出发点来探讨这个问题(以下讨论建立在石碓里石头数量充分的前提下):如果轮到我们去取的时候,石碓里还剩4颗石头,而在这之前,一定是另外一个人取了一次,导致石碓里还剩4颗石头,那么另外一个人在取的时候,石碓里还剩多少颗石头呢?这里只能有三种情况:

第一种情况:4 + 1 = 5

第二种情况:4 + 2 = 6

第三种情况:4 + 3 = 7

也就是说,如果轮到另外一个人去取石头时,石碓里的数目为以上三种情况之一,那么他总能够通过适当的取法,使得石碓里剩余石头的数目为4,这样当轮到我们去取时,我们必输。

在这三种情况的基础上进一步往下考虑,注意到

5 + 3 = 8

6 + 2 = 8

7 + 1 = 8

也就是说,如果轮到我们去取时,石碓里剩下的数目为8,那么不论我们怎么取,石碓中剩余的数目必然落在集合 {5, 6, 7} 之内,此时轮到另外一个人去取,这就又回到了刚才的情况——他总能通过适当的取法使石碓中剩余的数目变为4,这样我们必输。

综合以上讨论,如果当我们去取时,石碓中的数目是4或者8,那么不管我们怎么取,最终的结果都是必输(因为另外一个人也跟我们一样聪明)。注意到4和8都是4的倍数,而且遇到4和8时我们必输,但反过来遇到 {1, 2, 3} 或 {5, 6, 7} 时我们必赢,由此我们大胆猜测:在我们先取的情况下,当石碓中的数目为4的倍数时,我们必输,而除此之外,其他所有情况我们都必赢。

通过简单的验证不难发现以上猜测的正确性。

代码实现(个人版):

1 class Solution:
2     def canWinNim(self, n: int) -> bool:
3         if n // 4 != 0 and n % 4 == 0:
4             return False
5         else:
6             return True

代码实现(大神版):

1 class Solution:
2     def canWinNim(self, n: int) -> bool:
3         return n % 4 != 0

对比:其实我个人的代码和大神的代码思路是完全一样的,区别在于:

(1)直观上看,不够简洁(大神的代码仅用一个表达式就实现了),原因是没有充分理解正则表达式的应用;

(2)额外考虑了初始石碓数目小于4的情况,其实没必要考虑。

原文地址:https://www.cnblogs.com/tbgatgb/p/10921302.html