LeetCode-292 Nim 游戏
292. Nim 游戏
难度简单478
你和你的朋友,两个人一起玩 Nim 游戏:
- 桌子上有一堆石头。
- 你们轮流进行自己的回合,你作为先手。
- 每一回合,轮到的人拿掉 1 - 3 块石头。
- 拿掉最后一块石头的人就是获胜者。
假设你们每一步都是最优解。请编写一个函数,来判断你是否可以在给定石头数量为 n
的情况下赢得游戏。如果可以赢,返回 true
;否则,返回 false
。
示例 1:
输入:n = 4
输出:false
解释:如果堆中有 4 块石头,那么你永远不会赢得比赛;
因为无论你拿走 1 块、2 块 还是 3 块石头,最后一块石头总是会被你的朋友拿走。
示例 2:
输入:n = 1
输出:true
示例 3:
输入:n = 2
输出:true
提示:
1 <= n <= 231 - 1
思考过程:
我们作为先手,,来看看n的几种情况。
当n<=3 时,我们必赢。
当n=4时,我们必输, 因为无论我们拿走 1 块、2 块 还是 3 块石头,最后一块石头总是会被我们的朋友拿走。
当n=5时,下面有几种情况:
- 拿1块,那么朋友有4块石头等待选择。
- 拿2块,那么朋友有3块石头等待选择。
- 拿3块,那么朋友有2块石头等待选择。
这里细心的发现,当我们走x块石头,那么朋友就进入到n-x块石头的情况,所以他选择的输赢结果就是我们选择输赢结果的取取反。
这里用dp思想很容易写出代码,n表示石头数量,a(n)等于我们输赢的结果,值为真假。
func canWinNim(n int) bool {
if n < 4 {
return true
}
arr := make([]bool, n)
arr[0], arr[1], arr[2] = true, true, true
for i := 3; i < n; i++ {
arr[i] = !arr[i-1] || !arr[i-2] || !arr[i-3]
}
return arr[n-1]
}
但是很遗憾,这样通不过题解,leetcode会超时。
让我们换个思路,现在我们来找找规律。
n | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
a(n) | true | true | true | false | true | true | true | false |
我们发现a(n)其实是个周期函数,T=4。
所以我们对n取模可得下面的代码:
func canWinNim(n int) bool {
return n%4 > 0
}