算法 - leetcode 292 Nim Game

Posted timfruit

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法 - leetcode 292 Nim Game相关的知识,希望对你有一定的参考价值。

算法 - leetcode 292 Nim Game

 一丶题目

你和你的朋友,两个人一起玩 Nim 游戏:桌子上有一堆石头,每次你们轮流拿掉 1 - 3 块石头。 拿掉最后一块石头的人就是获胜者。你作为先手。

你们是聪明人,每一步都是最优解。 编写一个函数,来判断你是否可以在给定石头数量的情况下赢得游戏。


输入: 4
输出: false 
解释: 如果堆中有 4 块石头,那么你永远不会赢得比赛;
     因为无论你拿走 1 块、2 块 还是 3 块石头,最后一块石头总是会被你的朋友拿走。

 

二丶思路

  1) 先尝试使用暴力解决--递归

  

class Solution 
    public boolean canWinNim(int n) 
        if(n<=0)
            return false;
        
        if(n<=3)
            return true;
        
        if(!friendCanWinNim(n-1)) //拿1块
            return true;
        
        if(!friendCanWinNim(n-2)) //拿2块
            return true;
        
        if(!friendCanWinNim(n-3)) //拿3块
            return true;
        
        return false;
    

    //朋友拿, 朋友是否可以赢
    private boolean friendCanWinNim(int n)
        if(n<=0)
            return false;
        
        if(n<=3)
            return true;
        
        if(!canWinNim(n-1)) //拿1块
            return true;
        
        if(!canWinNim(n-2)) //拿2块
            return true;
        
        if(!canWinNim(n-3)) //拿3块
            return true;
        
        return false;
    

 

 

  2) 出现超时的现象,缓存中间结果

class Solution 
    Map<Integer, Boolean> resultMap =new HashMap<Integer, Boolean>(); //结果
    
    public boolean canWinNim(int n) 
        if(n<=0)
            return false;
        
        if(n<=3)
            return true;
        
        if(results[n]!=null)
            return results[n];
        

        boolean result=false;
        if(!friendCanWinNim(n-1)) //拿1块
            result=true;
            resultMap.put(n, result);return result;
        
        if(!friendCanWinNim(n-2)) //拿2块
            result=true;
            resultMap.put(n, result);return result;
        
        if(!friendCanWinNim(n-3)) //拿3块
            result=true;
            resultMap.put(n, result);return result;
        

        result=false;
        resultMap.put(n, result);return result;
    

    //朋友拿, 朋友是否可以赢
    private boolean friendCanWinNim(int n)
        if(n<=0)
            return false;
        
        if(n<=3)
            return true;
        
        if(!canWinNim(n-1)) //拿1块
            return true;
        
        if(!canWinNim(n-2)) //拿2块
            return true;
        
        if(!canWinNim(n-3)) //拿3块
            return true;
        
        return false;
    

 

 

  3) 递归过大, 出现栈溢出异常, 将递归改成for循环 (类似动态规划)

 

class Solution 
    Map<Integer, Boolean> resultMap =new HashMap<Integer, Boolean>(); //缓存先手的结果
    public boolean canWinNim(int n) 
       if(n<=0)
            return false;
        
        // 初始化
        resultMap.put(1, true);
        resultMap.put(2, true);
        resultMap.put(3, true);

        boolean result1, result2, result3;
        for(int i=4;i<=n;i++)
            // 拿1块
            result1=resultMap.get(i-1);

            // 拿2块
            result2=resultMap.get(i-2);

            // 拿3块
            result3=resultMap.get(i-3);

            if(!result1 || !result2 || !result3)
                resultMap.put(i, true);
            else 
                resultMap.put(i, false);
            

       System.out.println(i+" -> "+resultMap.get(i));
return resultMap.get(n);

 

  4) 仍然出现超时, (打印中间结果可发现规律 T_T 这里看了别人的解释)

class Solution 
    public boolean canWinNim(int n) 
        //规律题
        // 3+1  必输
        return n%(3+1)!=0;
    

 

以上是关于算法 - leetcode 292 Nim Game的主要内容,如果未能解决你的问题,请参考以下文章

Leetcode刷题100天—292. Nim 游戏( 数学)—day42

Leetcode刷题100天—292. Nim 游戏( 数学)—day42

LeetCode刷题292-简单-Nim游戏

LeetCode刷题292-简单-Nim游戏

LeetCode 292. Nim Game

Leetcode 292. Nim Game