首页 > 其他 > 详细

292_Nim Game

时间:2019-10-17 22:59:07      阅读:70      评论:0      收藏:0      [点我收藏+]

292_Nim Game

一、题目详情

技术分享图片

??题目的意思是给定石头的数量n,双方每次只能拿1-3个石头,己方先手,问在给定n后,自己能不能获胜。

二、解题方法

第一种方法(Time Limit Exceeded)

??一开始拿到题目,我的第一想法是使用博弈树的思想解题,当节点状态是己方行动&&石子数量<=3获胜,当节点是对方行动&&石子数量<=3失败。因为双方都足够聪明,所以要在对手每一步取走1个,2个,3个石子都必须取胜。代码如下:

class Solution {
    public boolean canWinNim(int n) {
        return canWinNimHelper(n,true);
    }
    //isSelf==true表示己方行动,false表示对手行动
    public boolean canWinNimHelper(int n,boolean isSelf){
        if(n<=3&&isSelf) return true;
        if(n<=3&&!isSelf) return false;
        if(isSelf)
            return canWinNimHelper(n-1,!isSelf)
                || canWinNimHelper(n-2,!isSelf)
                || canWinNimHelper(n-3,!isSelf);
        else
            return canWinNimHelper(n-1,!isSelf)
                && canWinNimHelper(n-2,!isSelf)
                && canWinNimHelper(n-3,!isSelf);
    }
}

??不出意料这种方法Time Limit Exceeded.

第二种方法(Memory Limit Exceeded)

??因为上面这种算法超时,我观察了一下该算法,可以使用动态规划的思想解决超时问题。算法具体为:现在求得是由n个石子是否能赢,则只要拿走1个棋子或者两个棋子或者三个棋子后,对方会输就行(己方和对方是一样的,dp[i]只表示现在行动的那方能不能赢)。所以就有:
dp[i] = !(dp[i-1]&&dp[i-2]&&dp[i-3])

class Solution {
    public boolean canWinNim(int n) {
        if(n<=3) return true;
        boolean[] dp = new boolean[n+1];
        dp[1] = true;dp[2]=true;dp[3]=true;
        for(int i=4;i<=n;i++){
            dp[i] = !(dp[i-1]&&dp[i-2]&&dp[i-3]);
        }
        return dp[n];
    }
}

??这个我以为可以accept,但是题目给的数据太大,建立dp数组太耗空间,但是这里可以改进一下:因为dp时只需要i的i-1,i-2,i-3的值,所以可以只保留这三个,这样就解决了内存的问题。

第三种方法(Accept)

??这种方法比较特殊。只要n不能被4整除自己就能赢。
解释:我们可以知道当n=1,2,3时我们可以赢,当n=4时我们会输。当n=5,6,7时,我们可以对应的拿掉1,2,3个石子让对方行动时只有4个棋子,我们就能赢。n=8时,我们会输。以此类推,只要n不能被4整除自己就能赢。

class Solution {
    public boolean canWinNim(int n) {
        return !(n%4==0);
    } 
}

292_Nim Game

原文:https://www.cnblogs.com/Mrfanl/p/11695378.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!