硬币排成线关注问题 O(1) 时间复杂度且O(1) 存储。 2020-08-27

硬币排成线关注问题

  • 描述

    ENG

    有 n 个硬币排成一条线。两个参赛者轮流从右边依次拿走 1 或 2 个硬币,直到没有硬币为止。拿到最后一枚硬币的人获胜。

    请判定 先手玩家 必胜还是必败?

    若必胜, 返回 true, 否则返回 false.

    您在真实的面试中是否遇到过这个题?  是

    题目纠错

    样例

    样例 1:

    输入: 1
    输出: true
    

    样例 2:

    输入: 4
    输出: true
    解释: 
    先手玩家第一轮拿走一个硬币, 此时还剩三个.
    这时无论后手玩家拿一个还是两个, 下一次先手玩家都可以把剩下的硬币拿完.
    

    挑战

    O(1) 时间复杂度且O(1) 存储。

  • 原理1:

  • 本题一个人可以拿1个或者2个,如果输入的n符合条件,为了确保第一个人拿一定能够赢,则对拿法一定要有要求:第一个人在第一次拿之后一定要保证剩下的物品数量为3的倍数,接下来无论第二个人怎么拿,第一个人还是能把剩下的物品数量控制在3的倍数,因此第一个人一定能够确保自己拿到最后一枚硬币并获胜。因此对于输入的数n,是3或者3的倍数个 先手必败,其它情况选手必胜。

  • 代码1:

  • public class Solution {
        /**
         * @param n: An integer
         * @return: A boolean which equals to true if the first player will win
         */
        public boolean firstWillWin(int n) {
            // write your code here
            return n%3!=0;
        }
    }

    原理2:

  • 博弈:

  • 一个状态是先手必胜状态 当且仅当 它的子状态中存在一个 先手必败状态
    状态f[i]: 还有i个硬币时 是否是先手必胜
    状态转移: f[i] = f[i - 1] == false || dp[i - 2] == false;
    初始条件: f[1] = f[2] = true;
    计算顺序: 从小到大
    返回: f[n]
    可以用滚动数组优化

  • 代码2:

  • public class Solution {
        /**
         * @param n: An integer
         * @return: A boolean which equals to true if the first player will win
         */
        public boolean firstPlayer(int n) {
            // write your code here
            boolean []f = new boolean[n+2];
            f[0] = false;
            f[1] = true;
            for(int i=2; i<=n; ++i)
                f[i] = !f[i-1] || !f[i-2];
            return f[n];
        }
    }

     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值