问题:
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.
For example, 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.
看到这个题目,我的第一个想法是使用递归,类似于汉诺塔:
public class Solution { public boolean canWinNim(int n) { if(n == 1 || n ==2 || n == 3) return true; else return canWinNim(n-1) || canWinNim(n-2) || canWinNim(n-3); } }
这个方案对于小数字可以解决问题。但是对于大数,如1348820612就会产生StackOverFlowException。
查看讨论之后发现,解法其实非常简单
public class Solution { public boolean canWinNim(int n) { return n % 4 != 0 } }
下面讨论一下为什么这个解法是对的。
首先,题目给出了提示,如果只剩下4个石子,那么你先手,必输。另一个假设,对手也是非常聪明的,总能选择最优的解法对付你。这就提示,想赢,必须让对方必输。
或者说,只要我们找到一种能够赢的方法,就可以解决这个问题。只要做到最后剩下的石子数不超过4就行了。换句话说,对方想赢,那么最后剩下的石子数必须是4,否则我就能够赢。
顺着这个思路,我们先来看看5~8个石子的情形,以下第一个数代表我取的石子数,依次类推
5个:我取走1个,剩下4个,对方必输
6个:我取走2个,剩4个,对方必输
7个:我取走3个,剩4个,对方必输
8个:无论我取几个,对方都可以让石子剩下4个,我必输
那么对于9~12个呢,只要我能让我取完后剩下的石子是8个,我就必赢。
重复上述过程,也就是我拿走后能够剩下4的倍数,那么我就可以保证胜利。加上我先手拿掉了1、2、3,那么只要不是4的倍数个石子,我都可以获胜。
于是解法就成了,对4取余。
浙公网安备 33010602011771号