难度:中等
目录
一、问题描述
这里我直接采用的LeetCode上面的问题描述。
Alice 和 Bob 再次设计了一款新的石子游戏。现有一行 n 个石子,每个石子都有一个关联的数字表示它的价值。给你一个整数数组 stones ,其中 stones[i] 是第 i 个石子的价值。
Alice 和 Bob 轮流进行自己的回合,Alice 先手。每一回合,玩家需要从 stones
中移除任一石子。
- 如果玩家移除石子后,导致 所有已移除石子 的价值 总和 可以被 3 整除,那么该玩家就 输掉游戏 。
- 如果不满足上一条,且移除后没有任何剩余的石子,那么 Bob 将会直接获胜(即便是在 Alice 的回合)。
假设两位玩家均采用 最佳 决策。如果 Alice 获胜,返回 true
;如果 Bob 获胜,返回 false
。
下面给出示例:
提示:
1 <= stones.length <= 105
1 <= stones[i] <= 104
二、解题思想
将所有 stones 的价值全部跟 3 求余后,那么所有石子的价值只有三种 0、1、2 :
- 可以被 3 整除的 记为 0 用 zeroQuantity表示其个数。
- 不能被 3 整除的余 1 记为 1用 oneQuantity 表示其个数。
- 不能被 3 整除的余 2 记为 3用 twoQuantity 表示其个数。
要想总价值不能被 3 整除,在Alice先手的且没有zeroQuantity的情况下:
- 如果Alice拿 1 那么顺序只能是 1121212121......。
- 如果Alice拿 2 那么顺序只能是 2212121212......。
根据以上情况得出Alice的决策后果:
- 如果Alice起手拿 1 那么,Alice后面只能拿2,Bob后面只能拿1。
- 如果Alice起手拿 2 那么,Alice后面只能拿1,Bob后面只能拿2。
现在来考虑 0 的情况 ,先手不能拿 0 ,因为0直接就可以被3整除,那么除了先手,之后都可以拿 0 ,我们不妨假设所有的 0 都是最后取,即把所有的 1 和 2 全部取完后 或者剩下的不论取啥都能够使得总价值被 3 整除,此时剩下的最后两人轮流取 0 。
0很独特,奇数个0可以视为反转了Alice的决策后果即有奇数个0时:
- 如果Alice起手拿 1 那么,Alice后面只能拿1,Bob后面只能拿2。
- 如果Alice起手拿 2那么,Alice后面只能拿2,Bob后面只能拿1。
当zeroQuantity为偶数时:
- 只有一个 1 或 一个 2 (Bob赢得游戏,因为被取光了)
- 当有超过一个1 和超过一个2时,Alice能够根据最佳觉得选择先手拿什么来让自己取得胜利。(Alice赢得游戏,因为根据决策后果:Alice可以让对手拿少的那个)
- 例如:
- [1,1,2,2,1] 顺序为:2 2 1 1 (Alice赢得游戏,Bob拿的总价值可以被3整除)
- [1,1,1,1,1,2,2,2] 顺序为 2 2 1 2 1 1 (Alice赢得游戏,Bob拿总价值可以被3整除)
- 2 比1 多的情况则同理
当zeroQuantity为奇数时:
以上Alice的决策后果则被反转给自己了。
例如:
- [1,1,1,2,2,0] 顺序为:2 2 1 0 1 (Bob赢得游戏,此时Alice拿的总价值可以被3整除)
但是当 oneQuantity 与 twoQuantity 的数量差在2以上时 奇数个0将失效:
- [1,1,1,1,2,0] 顺序为 :1 1 2 1 0 1 或 1 1 0 2 1 1 此时(Alice赢得游戏,Bob拿的总价值可以被3整除)
三、解题
1、判断极端情况
此题无特殊极端情况。
2、代码实现
bool stoneGameIX(vector<int>& stones) {
if(stones.size() == 1){
return false;
}
int zeroQuantity = 0, oneQuantity = 0, twoQuantity = 0;
for(auto &it: stones){
it = it % 3;
if(it == 0){
zeroQuantity++;
}else if(it == 1){
oneQuantity++;
}else if(it == 2){
twoQuantity++;
}
}
if(!(zeroQuantity%2)){
return oneQuantity>=1 && twoQuantity>=1;
}
return (oneQuantity-twoQuantity>2) || (twoQuantity-oneQuantity>2);
}