LeetCode 每日一题 [2029]石子游戏 IX


一道Medium难度(狗屁)的博弈论题,AC率45.3%(手动狗头)。这道题的难度已经远远超过中等难度了,Hard至少一半没有这个难,而且博弈论属于现代数学的一个分支,是运筹学的子类,多用在金融数学,所以这道题对逻辑思维和数学能力要求很高。引用一下一位大佬的评论:

https://leetcode.com/discuss/general-discussion/1500149/weekly-contest-261 官方把这个题放在了第三题的位置(此题的存在也使得2030题的竞赛分远远超过实际难度),引来了美国站用户的不满,并直接导致了博弈题目从此退出LeetCode平台,周赛第三题在放水的道路上越走越远(第三题难度达不到”中等“的情况,此题之前极其罕见,此题以后我已经见过4次)……

这个题目标“中等”是非常过分的,做不出来很正常,如果实在不会就来题解区学习标准做法,不要轻易气馁~

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

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

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

先借一张大佬的逻辑图

由于目标是3的倍数,那么我们可以把石子的价值看做除以3的余数,也就是0,1,2,对应石子的数量分别为nums[0],nums[1],nums[2]。

移除类型0的石子可以看做先后手交换:

  • 如果类型 0 的石子的个数为偶数,那么胜负情况等价于没有类型 0 的石子的胜负情况;
  • 如果类型 0 的石子个数为奇数,那么胜负情况等价于只有 1 个类型 0 的石子的胜负情况。注意这里不能单纯地等价于「没有类型 0 的石子的胜负情况」的相反情况,这是因为如果所有的石子都被移除完,无论谁移除了最后一个石子,都算 Alice 输。因此如果 Alice 发现自己选择移除类型 1 或 2 的石子不能获胜,于是选择移除类型 0 的石子,并且它不能获胜的原因是「石子会移除完」,那么 Alice 仍然会输。

将类型  的石子考虑完全之后,我们就还剩下类型  和  的石子了。可以发现,为了保证移除石子的和不为  的倍数,操作顺序只有可能为下面的两种情况:

  • 如果 Alice 首先移除类型  的石子,那么 Bob 只能移除类型  的石子,在这之后 Alice 只能移除类型  的石子,Bob 同样只能移除类型  的石子。以此类推,移除石子的类型序列为:

  • 如果 Alice 首先移除类型  的石子,我们可以类似得到移除石子的类型序列为:

总结

  • 如果  的数量为偶数,因为  先手,只要  和  皆大于  即可,则  赢。
  • 如果  的数量为奇数,相当于在  和  的序列里面可以插一个 ,因为 Alice 先手,只要  和  之间绝对之差大于 ,则  赢。

解释一下如果  的数量为奇数,为什么是  和  之间绝对之差大于 

  • 首先, 肯定不会选择 ,一定会选择  或者 ,以选  举例来说。
  •  选了 ,那么  能选  或者 
    • 如果  选了 ,那么  下轮只能选 ,后面  选 ,所以最后的序列为 1 0 1 2 1 2 1...,可以看出  的数量必须要比  的数量至少多 
    • 如果  选了 ,那么  下轮可以能选  或者 ,可以枚举  选的情况,可以发现最后的序列和上面类似,都是在 1和2的序列里面插入一个.
  •  选了 ,和上面同理,结果是和选  相反,  的数量必须要比  的数量至少多 

这样的话代码就如下:

class Solution {
    public boolean stoneGameIX(int[] stones) {
        int[] nums = new int[3];
        for (int i = 0; i < stones.length; i++) {
            nums[stones[i] % 3]++;
        }
        if (nums[0] % 2 == 0) {
            return nums[1] > 0 && nums[2] > 0;
        } else {
            return nums[1] - nums[2] > 2 || nums[2] - nums[1] > 2;
        }
    }
}

时间复杂度:O(n)

空间复杂度:O(1)

相关