leetcode 292 NimGame

1.问题描述

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.

你和你的朋友,两个人一起玩 Nim 游戏:

桌子上有一堆石头。
你们轮流进行自己的回合,你作为先手。
每一回合,轮到的人拿掉 1 - 3 块石头。
拿掉最后一块石头的人就是获胜者。
假设你们每一步都是最优解。请编写一个函数,来判断你是否可以在给定石头数量为 n 的情况下赢得游戏。如果可以赢,返回 true;否则,返回 false 。

注意,石头的堆的数量为偶数,所以你们两人拿走的堆数一定是相同的。
石头的总数为奇数,也就是你们最后不可能拥有相同多的石头,一定有胜负之分。

2.解法1

这个问题,看上去有点像斐波那契数列的问题。我们先用斐波那契数列的思路来解一下。

    private static boolean winGamev1(int n) {
    	// 最后一个没了,说明最后一个被对手拿到了,你输了。
    	// 如果最后剩的个数小于4个,即还剩1个,2个或者3个,你都赢了。
        if (n == 0) {
            return false;
        } if (n < 4) {
            return true;
        }
        for(int i=1; i<=3; i++) {
            //对方不管拿走 1 个,2 个,3 个, 你都可以获胜
            if (winGamev1(n-i-1) && winGamev1(n-i-2) && winGamev1(n-i-3)) {
                return true;
            }
        }
        return false;
    }

上面的代码可以完成相应的功能。但是很明显,效率很低,因为会有递归调用方法的问题,当n变大以后,复杂度会非常高。

3.解法2

遇到这种复杂的问题,我们经常使用的一种方式是反推法。
如果最后一轮要自己获胜,最后剩余的石头需要是1颗,2颗,或者3颗,这样能一次性拿完。
那么,等对手最后一次拿的时候,如果剩下的是4颗石头,那么不管他拿1颗,2颗,还是3颗,剩下的石头肯定是在1-3颗。
那如何使对手最后一次拿的时候还剩4颗石头呢?如果我们能使我们自己选择的时候还剩5颗,6颗,或者7颗石头,这样的话能保证对手拿的时候还剩4颗石头。

所以这么一直推导下去会发现,只要谁拿石子的时候,是4的倍数,那就一定会输。

所以最终的解法非常简单

    private static boolean winGamev2(int n) {
        return n % 4 != 0;
    }

只要n % 4 != 0,那么先手一定能获胜。

猜你喜欢

转载自blog.csdn.net/bitcarmanlee/article/details/114022435