|
| 1 | +### 题目描述 |
| 2 | + |
| 3 | +这是 LeetCode 上的 **[2029. 石子游戏 IX](https://leetcode-cn.com/problems/stone-game-ix/solution/gong-shui-san-xie-fen-qing-kuang-tao-lun-h1oa/)** ,难度为 **中等**。 |
| 4 | + |
| 5 | +Tag : 「博弈论」 |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | +`Alice` 和 `Bob` 轮流进行自己的回合,`Alice` 先手。每一回合,玩家需要从 `stones` 中移除任一石子。 |
| 10 | + |
| 11 | +如果玩家移除石子后,导致 所有已移除石子 的价值 总和 可以被 3ドル$ 整除,那么该玩家就 输掉游戏 。 |
| 12 | +如果不满足上一条,且移除后没有任何剩余的石子,那么 `Bob` 将会直接获胜(即便是在 `Alice` 的回合)。 |
| 13 | +假设两位玩家均采用 最佳 决策。如果 `Alice` 获胜,返回 `true` ;如果 `Bob` 获胜,返回 `false` 。 |
| 14 | + |
| 15 | +示例 1: |
| 16 | +``` |
| 17 | +输入:stones = [2,1] |
| 18 | + |
| 19 | +输出:true |
| 20 | + |
| 21 | +解释:游戏进行如下: |
| 22 | +- 回合 1:Alice 可以移除任意一个石子。 |
| 23 | +- 回合 2:Bob 移除剩下的石子。 |
| 24 | +已移除的石子的值总和为 1 + 2 = 3 且可以被 3 整除。因此,Bob 输,Alice 获胜。 |
| 25 | +``` |
| 26 | +示例 2: |
| 27 | +``` |
| 28 | +输入:stones = [2] |
| 29 | + |
| 30 | +输出:false |
| 31 | + |
| 32 | +解释:Alice 会移除唯一一个石子,已移除石子的值总和为 2 。 |
| 33 | +由于所有石子都已移除,且值总和无法被 3 整除,Bob 获胜。 |
| 34 | +``` |
| 35 | +示例 3: |
| 36 | +``` |
| 37 | +输入:stones = [5,1,2,4,3] |
| 38 | + |
| 39 | +输出:false |
| 40 | + |
| 41 | +解释:Bob 总会获胜。其中一种可能的游戏进行方式如下: |
| 42 | +- 回合 1:Alice 可以移除值为 1 的第 2 个石子。已移除石子值总和为 1 。 |
| 43 | +- 回合 2:Bob 可以移除值为 3 的第 5 个石子。已移除石子值总和为 = 1 + 3 = 4 。 |
| 44 | +- 回合 3:Alices 可以移除值为 4 的第 4 个石子。已移除石子值总和为 = 1 + 3 + 4 = 8 。 |
| 45 | +- 回合 4:Bob 可以移除值为 2 的第 3 个石子。已移除石子值总和为 = 1 +たす 3 +たす 4 +たす 2 =わ 10. |
| 46 | +- 回合 5:Alice 可以移除值为 5 的第 1 个石子。已移除石子值总和为 = 1 +たす 3 +たす 4 +たす 2 +たす 5 =わ 15. |
| 47 | +Alice 输掉游戏,因为已移除石子值总和(15)可以被 3 整除,Bob 获胜。 |
| 48 | +``` |
| 49 | + |
| 50 | +提示: |
| 51 | +* 1ドル <= stones.length <= 10^5$ |
| 52 | +* 1ドル <= stones[i] <= 10^4$ |
| 53 | + |
| 54 | +--- |
| 55 | + |
| 56 | +### 分情况讨论博弈 |
| 57 | + |
| 58 | +为了方便,我们用 `A` 来代指 `Alice`,用 `B` 带代指 `Bob`。 |
| 59 | + |
| 60 | +`A` 只有一种获胜方式,是使得 `B` 在选石子时凑成 3ドル$ 的倍数;而 `B` 除了能够通过让 `A` 凑成 3ドル$ 的倍数以外,还能通过让游戏常规结束来获胜。 |
| 61 | + |
| 62 | +因此整个游戏过程,我们只需要关心「已被移除的石子总和」和「剩余石子个数/价值情况」即可。 |
| 63 | + |
| 64 | +更进一步的,我们只需关心已被移除的石子总和是否为 3ドル$ 的倍数,以及剩余石子的价值与已移除石子总和相加是否凑成 3ドル$ 的倍数即可。 |
| 65 | + |
| 66 | +所以我们可以按照石子价值除以 3ドル$ 的余数分成三类,并统计相应数量。 |
| 67 | + |
| 68 | +不失一般性考虑,某个回合开始前,已移除的石子总和状态为 $x$(共三种,分别为除以 3ドル$ 余数为 0ドル$、1ドル$ 和 2ドル,ドル其中当状态为 0ドル,ドル且非首个回合时,说明凑成 3ドル$ 的倍数,游戏结束),剩余石子价值除以 3ドル$ 的余数 $s$ 分别为 0ドル$、1ドル$ 和 2ドル$。 |
| 69 | + |
| 70 | +**首先如果当前 $x = 1$ 时,不能选择 $s = 2$ 的石子,否则会导致凑成总和为 3ドル$ 的倍数而失败;同理 $x = 2$ 时,不能选择 $s = 1$ 的石子;而选择 $s = 0$ 的数字,不会改变 $x$ 的状态,可看做换手操作。** |
| 71 | + |
| 72 | +**同时成对的 $s = 0$ 的等价于没有 $s = 0$ 的石子(双方只需要轮流选完这些 $s = 0$ 的石子,最终会回到先手最开始的局面);而选择与 $x$ 相同的 $s$ 会导致 $x$ 改变(即 $x = 1$ 时,选择 $s = 1$ 的石子,会导致 $x = 2$;而 $x = 2$ 时,选 $s = 2$ 的石子,会导致 $x = 1$)。** |
| 73 | + |
| 74 | +明确规则后,是分情况讨论的过程: |
| 75 | + |
| 76 | +* **$s = 0$ 的石子数量为偶数**:此时等价于没有 $s = 0$ 的石子,我们只需要关心 $s = 1$ 和 $s = 2$ 即可: |
| 77 | + |
| 78 | + * **$s = 1$ 的石子数量为 0ドル$**: 这意味着 `A` 开始选择的只能是 $s = 2,ドル此时交给 `B` 的局面为「$x = 2$、剩余石子只有 $s = 2$」,此时 `B` 只能选 $s = 2$ 的石子,由于 $x = 2$ 且选择的石子 $s = 2,ドル因此交由回 `A` 的局面为「$x = 1,ドル剩余是在只有 $s = 2$」,因此游戏继续的话 `A` 必败,同时如果在该过程的任何时刻石子被取完,也是 `B` 直接获胜,即 **`A` 仍为必败**; |
| 79 | + |
| 80 | + * **$s = 2$ 的石子数量为 0ドル$**:分析同理,`A` 只能选 $s = 1,ドル此时交给 `B` 的局面为「$x = 1$、剩余石子只有 $s = 1$」,此时 `B` 只能选 $s = 1$ 的石子,由于 $x = 1$ 且选择的石子 $s = 1,ドル因此交由回 `A` 的局面为「$x = 2,ドル剩余是在只有 $s = 1$」,因此游戏继续的话 `A` 必败,同时如果在该过程的任何时刻石子被取完,也是 `B` 直接获胜,即 **`A` 仍为必败**; |
| 81 | + |
| 82 | + * **$s = 1$ 和 $s = 2$ 的石子数量均不为 0ドル$**:`A` 选数量不是最多的一类石子,`B` 下一回合只能选择相同类型的石子(或是无从选择导致失败),然后游戏继续,最终 `B` 会先进入「只能凑成 3ドル$ 的倍数」的局面导致失败,即 **`A` 必胜。** |
| 83 | + |
| 84 | +* **$s = 0$ 的石子数量为奇数**:此时等价于有一次换手机会,该换手机会必然应用在「对必败局面进行转移」才有意义,因此只有 $s = 1$ 和 $s = 2$ 的石子数量差大于 2ドル,ドル`A` 的先手优势不会因为存在换手机会而被转移: |
| 85 | + |
| 86 | + * **两者数量差不超过 2ドル$**:此时 `B` 可以利用「对方凑成 3ドル$ 的倍数必败」规则和「优先使用 $s = 0$ 石子」权利来进入确保自己为必胜态: |
| 87 | + |
| 88 | + * 举个 🌰,当 $s = 1$ 和 $s = 2$ 的石子数量相等,虽然有 $s = 0$ 的石子,`A` 先手,但是 `A` 的首个回合必然不能选 $s = 0,ドル否则马上失败结束,因此 `A` 只能选 $s = 1$ 或 $s = 2,ドル此时 `B`直接选择 $s = 0$ 的石子,交由给 `A` 的局面 $x$ 没有发生改变,`A` 只能选择与首个回合相同的 $s$ 游戏才能继续,因此局面会变为「`B` 先手、$s = 1$ 和 $s = 2$ 的石子数量差为 2ドル$」,游戏继续,最终 `A` 会先遇到「只能凑成 3ドル$ 的倍数」的局面,即 **`B` 必胜**。 |
| 89 | + |
| 90 | + * 两者数量差不超过 2ドル$:此时无论 `A` 选择数量较少或较多的 `s`,`B` 都在第二回合马上使用 $s = 0$ 的石子进行换手,`A` 只能继续选与第一回合相同类型的的石子,游戏才能进行,最终 `A` 会先遇到「只能凑成 3ドル$ 的倍数」或「石子被取完」的局面,即 **`B` 必胜**。 |
| 91 | + |
| 92 | + * **两者数量差超过 2ドル$** :此时即使 `A` 只要确保第一次选择数量较多的 $s,ドル不管 `B` 是否使用「优先使用 $s = 0$」的石子,`A` 都有足够次数数量多 $s$ 来抵消换手(或是在 `B` 放弃使用 $s = 0$ 之后马上使用),最终都是 `B` 最先遇到「只能凑成 3ドル$ 的倍数」的局面,即 **`A` 获胜**。 |
| 93 | + |
| 94 | +代码: |
| 95 | +```Java |
| 96 | +class Solution { |
| 97 | + public boolean stoneGameIX(int[] stones) { |
| 98 | + int[] cnts = new int[3]; |
| 99 | + for (int i : stones) cnts[i % 3]++; |
| 100 | + return cnts[0] % 2 == 0 ? !(cnts[1] == 0 || cnts[2] == 0) : !(Math.abs(cnts[1] - cnts[2]) <= 2); |
| 101 | + } |
| 102 | +} |
| 103 | +``` |
| 104 | +* 时间复杂度:$O(n)$ |
| 105 | +* 空间复杂度:$O(1)$ |
| 106 | + |
| 107 | +--- |
| 108 | + |
| 109 | +### 最后 |
| 110 | + |
| 111 | +这是我们「刷穿 LeetCode」系列文章的第 `No.2029` 篇,系列开始于 2021年01月01日,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 |
| 112 | + |
| 113 | +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 |
| 114 | + |
| 115 | +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 |
| 116 | + |
| 117 | +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 |
| 118 | + |
0 commit comments