Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情。
一、题目描述
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 = [2],输出:false
解释:Alice 会移除唯一一个石子,已移除石子的值总和为 2 。 由于所有石子都已移除,且值总和无法被 3 整除,Bob 获胜。
二、思路分析
1、石子分类
根据题意石子分三类,数量余3为0的称为类型0,余3为1的称为类型1,余3为2的称为类型2。
由于在题目规则上进行游戏时需要保证移除石子和不整除3,因此类型0的选取实际上是对总量无影响的,但是如果类型0出现次数为奇数,回合会交换;如果为偶数则回合交换会抵消,判断时可忽略。
2、枚举回合信息
这里我们暂时忽略类型0的选择,只枚举类型1和类型2;
当Alice第一回合选择类型1,Bob只能选择类型1,接着Alice只能选择类型2,Bob只能选择类型1:
1️⃣11 21 21 21……
如果Alice第一回合选择类型2,Bob只能选择类型2,接着Alice只能选择类型1,Bob只能选择类型2:
2️⃣22 12 12 12……
这里可以发现,实际上Alice第一回合选择之后就奠定了Bob整局选取石子的类型了,
那么如果Alice想每一次都赢,那么就必须在过程中让Bob不得已选择另一个类型的石子;
对于情况1️⃣来说:
①第一回合Bob如果没有1可选,那么直接在第一回合就输了,此时需保证类型1有且仅有1个;
②第一回合平手,此时1的数量是2,第二回合Alice选择了2,此时如果Bob只有2可选也输了,后面的回合都是这种推演,这意味着类型2的数量应该大于或者等于类型1的数量;
对于情况2️⃣来说:
①第一回合Bob如果没有2可选,那么直接在第一回合就输了,此时需保证类型2有且仅有1个;
②第一回合平手,此时2的数量是2,第二回合Alice选择了1,此时如果Bob只有1可选也输了,后面的回合都是这种推演,这意味着类型1的数量应该大于或者等于类型2的数量;
综合以上两种情况,只要类型1和类型2的石子数量都大于等于1,那么Alice总可以找到一个方案去赢。
3、考虑回合交换
我们还需要考虑一下类型0为奇数时导致的回合交换,这会使得玩家选取石子的类型发生变化,但由于石子类型为偶数的情况不会导致回合交换,因此我们可以直接假设类型0的数量为1,来看几个例子:
1)当类型0的石子出现在第一回合,有四种可能性,分别为:
① 01 12 12……
② 10 12 12……
③ 02 21 21……
④ 20 21 21……
在①和②情况下,如果Alice想赢得游戏,就需要出现01 12 11或者10 12 11 等等,也就是需要类型1的数量至少比类型2多3个,即是 类型1-类型2 >= 3;
在③和④情况下,如果Alice想赢得游戏,就需要出现02 21 22或者20 21 22 等等,也就是需要类型2的数量至少比类型1多3个,即是 类型2-类型1 >= 3;
2)当类型0的石子出现在第一回合之外,有四种可能性,分别为:
① 11 02 12 12……
② 11 20 12 12……
③ 22 01 21 21……
④ 22 02 21 21……
我们可以发现实际上这和1)的情况是一致的,不过是类型0的位置变换了,回合数增加了,但Alice赢得游戏所需的条件仍是相同的;
因此我们可以得出结论:类型0石子为奇数时,Alice获胜的条件为类型1的数量至少比类型2多三个 或者 类型2的数量至少比类型1多三个。
4、总结
类型0数量为偶数时:类型1和类型2的石子数量都大于等于1;
类型0数量为奇数时:类型1的数量至少比类型2多三个 或者 类型2的数量至少比类型1多三个;
三、AC代码
class Solution {
public boolean stoneGameIX(int[] stones) {
int stone0 = 0;
int stone1 = 0;
int stone2 = 0;
for (int stone : stones) {
if (stone % 3 == 0) {
stone0++;
} else if (stone % 3 ==1) {
stone1++;
} else {
stone2++;
}
}
if (stone0 % 2 == 0) {
return stone1 >= 1 && stone2 >= 1;
}
return stone1 - stone2 >= 3 || stone2 - stone1 >= 3;
}
}