Leetcode 2029.石子游戏IX

题目

Alice 和 Bob 再次设计了一款新的石子游戏。现有一行 n 个石子,每个石子都有一个关联的数字表示它的价值。给你一个整数数组
stones ,其中 stones[i] 是第 i 个石子的价值。

Alice 和 Bob 轮流进行自己的回合,Alice 先手。每一回合,玩家需要从 stones 中移除任一石子。

如果玩家移除石子后,导致 所有已移除石子 的价值 总和 可以被 3 整除,那么该玩家就 输掉游戏 。
如果不满足上一条,且移除后没有任何剩余的石子,那么 Bob 将会直接获胜(即便是在 Alice 的回合)。 假设两位玩家均采用 最佳
决策。如果 Alice 获胜,返回 true ;如果 Bob 获胜,返回 false 。

示例1

输入:stones = [2,1]
输出:true 解释:游戏进行如下:

  • 回合 1:Alice 可以移除任意一个石子。
  • 回合 2:Bob 移除剩下的石子。 已移除的石子的值总和为 1 + 2 = 3 且可以被 3 整除。因此,Bob 输,Alice 获胜。

示例2

输入:stones = [5,1,2,4,3]
输出:false 解释:Bob 总会获胜。其中一种可能的游戏进行方式如下:

  • 回合 1:Alice 可以移除值为 1 的第 2 个石子。已移除石子值总和为 1 。
  • 回合 2:Bob 可以移除值为 3 的第 5 个石子。已移除石子值总和为 = 1 + 3 = 4 。
  • 回合 3:Alices 可以移除值为 4 的第 4 个石子。已移除石子值总和为 = 1 + 3 + 4 = 8 。
  • 回合 4:Bob 可以移除值为 2 的第 3 个石子。已移除石子值总和为 = 1 + 3 + 4 + 2 = 10.
  • 回合 5:Alice 可以移除值为 5 的第 1 个石子。已移除石子值总和为 = 1 + 3 + 4 + 2 + 5 = 15. Alice 输掉游戏,因为已移除石子值总和(15)可以被 3 整除,Bob 获胜。

思路

1,计算给定数组元素mod 3的结果,存入数组cnts中
我们将已移除的石头总和状态设为x(共三种,mod3=0,1,2,状态为0时且非收个回合时,说明凑成3的倍数,游戏结束),剩余石子价值mod3的余数s分别为0,1,2。
首先如果当前 x = 1 时,不能选择 s = 2的石子,否则会导致凑成总和为 3 的倍数而失败;同理 x=2 时,不能选择 s = 1 的石子;而选择 s=0 的数字,不会改变 x 的状态,可看做换手操作。

同时成对的 s=0的石子 等价于没有 s=0 的石子(双方只需要轮流选完这些 s=0 的石子,最终会回到先手最开始的局面);而选择与 x 相同的 s 会导致 x 改变(即 x=1 时,选择 s = 1 的石子,会导致 x=2;而 x = 2 时,选 s = 2 的石子,会导致 x=1)。
分情况讨论:
s=0的石子数量为偶数,等价于没有s=0的石子,我们关心s=1和s=2即可
如果s=1和s=2任意一个数量为0时,都是A败,因为A先手,三次选同一种石子,必然会是3的倍数,或者没有到第三次就结束了,那也是A输了。
如果s=1和s=2的数量均不等于0时,A必胜,A先手选数量较少的一类石子,那么B第一轮也只有选这一类,然后A就转换到选数量多的那一类去了,这样玩下去,那么就是B输,因为B那一类的石子不够用后,就要选A类的, 这样就会凑出3的倍数。
s=0的石子数量为奇数,等价于有一次换手机会
当s=1和s=2数量差不超过2时,此时B可以利用【对方凑成3的倍数必败】和【优先使用s=0石子】机会来进入确保自己为必胜的转态,A想赢,那肯定选石子数量多的一方,假如A第一次选的是s=1,B选s=0,那么接下来A还是只好选s=1,这样连续选俩次,那么石子数量多的一方就转换了,变成了s=2数量多了,接下来B选择的就是s=2,然后A会先遇到凑成3倍数的局面。
当s=1和s=2数量差超过了2,此时A只要确保第一次选择数量多的s,不管B是否使用s=0的石子,A都有足够数量的s来抵消这次换手,
最终会是B先遇到凑成3的局面,A获胜。

代码

public class 石子游戏_2029 {
     public static boolean stoneGameIX(int [] stones){
         int []cnts=new int [3];
         for (int i:stones)
             cnts[i%3]++;
         return cnts[0]%2==0?!(cnts[1]==0||cnts[2]==0):!(Math.abs(cnts[1]-cnts[2])<=2);
     }

    public static void main(String[] args) {
        int [] stones={2,1};
        System.out.println(stoneGameIX(stones));
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Brother汤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值