Easy
题目描述
Alice 和 Bob 正在玩一个游戏,他们轮流从一堆石子中移除石子,Alice 先手。
- Alice 在她的第一轮中恰好移除 10 个石子。
- 在每个后续轮次中,每个玩家移除的石子数恰好比前一个对手少 1 个。
无法行动的玩家输掉游戏。
给定一个正整数 n,如果 Alice 赢得游戏则返回 true,否则返回 false。
示例 1:
输入:n = 12
输出:true
解释:
- Alice 在她的第一轮移除 10 个石子,给 Bob 留下 2 个石子。
- Bob 无法移除 9 个石子,所以 Alice 获胜。
示例 2:
输入:n = 1
输出:false
解释:
- Alice 无法移除 10 个石子,所以 Alice 失败。
约束条件:
1 <= n <= 50
解题思路
解题思路
这是一个博弈论问题,我们需要分析游戏规则来确定获胜者。
游戏规则分析:
- Alice 第一轮移除 10 个石子
- Bob 第二轮移除 9 个石子(比 Alice 少 1)
- Alice 第三轮移除 8 个石子(比 Bob 少 1)
- 以此类推,每轮移除的石子数依次为:10, 9, 8, 7, 6, 5, 4, 3, 2, 1
解法一:模拟法 直接模拟游戏过程,轮流减去对应数量的石子,直到某一方无法继续。
解法二:数学分析(推荐) 我们可以预先计算出所有可能的游戏回合数:
- 如果石子总数不足以让 Alice 进行第一步(n < 10),Alice 直接失败
- 否则,我们可以计算游戏进行的总回合数,判断最后是哪一方无法行动
通过分析可以发现:
- 移除石子的序列是:10, 9, 8, 7, 6, 5, 4, 3, 2, 1
- 前 k 项的和为:10 + 9 + … + (11-k) = k*(21-k)/2
我们需要找到最大的 k 使得前 k 项和不超过 n,然后判断 k 的奇偶性。
代码实现
class Solution {
public:
bool canAliceWin(int n) {
if (n < 10) return false;
int stones = n;
int toRemove = 10;
bool aliceTurn = true;
while (stones >= toRemove) {
stones -= toRemove;
aliceTurn = !aliceTurn;
toRemove--;
}
return !aliceTurn;
}
};
class Solution:
def canAliceWin(self, n: int) -> bool:
if n < 10:
return False
stones = n
to_remove = 10
alice_turn = True
while stones >= to_remove:
stones -= to_remove
alice_turn = not alice_turn
to_remove -= 1
return not alice_turn
public class Solution {
public bool CanAliceWin(int n) {
if (n < 10) return false;
int stones = n;
int toRemove = 10;
bool aliceTurn = true;
while (stones >= toRemove) {
stones -= toRemove;
aliceTurn = !aliceTurn;
toRemove--;
}
return !aliceTurn;
}
}
var canAliceWin = function(n) {
if (n < 10) return false;
let stones = n;
let toRemove = 10;
let aliceTurn = true;
while (stones >= toRemove) {
stones -= toRemove;
aliceTurn = !aliceTurn;
toRemove--;
}
return !aliceTurn;
};
复杂度分析
| 解法 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| 模拟法 | O(√n) | O(1) |
| 数学法 | O(1) | O(1) |
说明: 模拟法的时间复杂度是 O(√n),因为最多进行约 √(2n) 轮游戏。由于题目约束 n ≤ 50,两种方法的实际性能差异很小。
相关题目
- . Stone Game IV (Hard)