2029. 石子游戏 IX

【博弈论 + 数学】LeetCode 石子游戏 IX - 解题详解与思维优化

🧩 题目描述

Alice 和 Bob 设计了一款新的石子游戏。一排共有 n 个石子,每个石子有一个整数值。游戏规则如下:

  • 两人轮流操作,Alice 先手。
  • 每次操作,玩家可以从中移除任意一个石子
  • 如果某一玩家移除石子后,使得已移除的所有石子总和可以被 3 整除,那么该玩家立刻输掉游戏
  • 如果所有石子被移除完毕,还没有触发上述输条件,则 Bob 获胜(即便最后一个石子是 Alice 拿的)。

假设 Alice 和 Bob 都采用最优策略,判断 Alice 是否可以获胜。

函数签名如下:

def stoneGameIX(self, stones: List[int]) -> bool

🧠 解题分析

这道题属于典型的博弈论类型。需要结合策略、数学和状态转移来判断“谁能赢”。

核心关注点:

  • 判断当前移除某个石子后,是否使已移除石子的和变为 3 的倍数
  • 由于我们只关心“总和是否能被 3 整除”,我们可以用 模 3 的结果对所有石子分类。
  • 将石子按照 value % 3 分为三类:
    • mod 0:余数为 0(对结果中性)
    • mod 1:余数为 1
    • mod 2:余数为 2

模 0 的石子对当前总和没有影响,但会改变总和“是否能被3整除”的可能性,因此也有重要作用。


🚀 解题方法一:数学归类 + 策略模拟(最终解法)

Step 1:按模 3 分类

统计三类石子的数量:

c = Counter(x % 3 for x in stones)
mod0 = c[0]
mod1 = c[1]
mod2 = c[2]

Step 2:策略讨论

我们考虑两种情况:

✅ 情况一:mod0 的个数是偶数

这表示“移除 mod0 的石子”不会让当前总和陷入被3整除的风险。此时,Alice 只要在 mod1 和 mod2 中有选择即可安全起手。

  • 胜利条件:mod1 > 0 且 mod2 > 0(Alice 可以用两类石子相互牵制)
✅ 情况二:mod0 的个数是奇数

此时移除 mod0 的数量会把当前的移除和转换成“被3整除”的状态,危险!

  • Alice 此时必须使用 mod1 或 mod2 打乱平衡。
  • 只有当 mod1 和 mod2 的差距大到能压制对手,即:abs(mod1 - mod2) >= 3,Alice 才有翻盘空间。

✅ 最终代码实现(简洁版)

from collections import Counter
from typing import List

class Solution:
    def stoneGameIX(self, stones: List[int]) -> bool:
        c = Counter(x % 3 for x in stones)
        if c[0] % 2 == 0:
            return c[1] > 0 and c[2] > 0
        return abs(c[1] - c[2]) >= 3

🔍 示例说明

示例 1:

输入: [2,1]
输出: True
  • 分别是 mod1 和 mod2,一共两个石子。
  • mod0 = 0(偶数),mod1 = 1,mod2 = 1
  • 满足:mod0 是偶数且 mod1, mod2 均非 0
  • ✅ Alice 可赢

示例 2:

输入: [2]
输出: False
  • 只有一个 mod2 的石子
  • mod0 = 0(偶数),但 mod1 = 0,不满足两个非零条件
  • ❌ Bob 赢

🤔 分析与比较

✅ 优点

  • 时间复杂度为 O(n),空间复杂度为 O(1)
  • 不需要模拟具体轮次,只关注石子的模值统计即可判断胜负
  • 用数学归纳替代搜索、剪枝,大大提升效率

❌ 常见误区

  • 以为必须模拟轮流出牌(搜索爆炸)
  • 忽略了 mod0 的影响(它会在奇偶数上改变输赢趋势)
  • 忘记 Bob 在石子用完后也可以直接赢(边界情况)

🧠 结论总结

这道题的关键在于:

  1. 将问题转化为模3意义下的博弈模型
  2. 理解 mod0 的“奇偶性”对全局策略的影响
  3. 记住 Bob 会在所有石子移除后直接获胜这一特殊规则

最终代码极度精炼,却隐藏了深刻的博弈策略和数学逻辑,是一道非常经典的博弈+数学分类讨论题目


📌 附:一行极简表达(代码高压缩版)

def stoneGameIX(self, stones: List[int]) -> bool:
    c = Counter(x % 3 for x in stones)
    return (c[1] > 0 and c[2] > 0) if c[0] % 2 == 0 else abs(c[1] - c[2]) >= 3

希望这篇文章能帮助你掌握这类“数学博弈”题型的本质策略。如果你觉得有收获,欢迎收藏/点赞/关注,未来我们会继续拆解更多 LeetCode 高质量题目!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值