Stone Game IX — Medium Problem & Solution
Alice and Bob take turns removing one stone, Alice first. A player loses immediately if, after their removal, the total value of all removed stones is…
- Difficulty: Medium
- Topics: Arrays, Math, Greedy, Counting, Game Theory
- Asked at: Amazon, Google, Directi
- Time limit: 2 s
- Memory limit: 256 MB
- Languages: JavaScript, TypeScript, Python, Java, C++, C, C#, Go, Kotlin, Swift, Rust, PHP and Ruby
Problem statement
Alice and Bob take turns removing one stone, Alice first. A player loses immediately if, after their removal, the total value of all removed stones is divisible by 3. If every stone is removed without that happening, Bob wins.
Assuming both play optimally, return whether Alice wins.
Example 1
Input: stones = [2,1]
Output: true
Explanation: Alice removes 2; Bob must remove 1, making the total 3.
Example 2
Input: stones = [2]
Output: false
Explanation: Alice removes the only stone and the game ends with Bob winning.
Example 3
Input: stones = [5,1,2,4,3]
Output: false
Constraints
1 <= stones.length <= 1000001 <= stones[i] <= 10000
How to solve Stone Game IX
Reduce to residues. Stones with residue 0 are pure turn-passers, so only the parity of c0 matters; the game itself is then a forced alternation between residues 1 and 2 that Alice must sustain.
Approach
- Count stones by residue mod 3 into
c0,c1,c2. - If
c0is even, Alice wins exactly when bothc1 >= 1andc2 >= 1. - If
c0is odd, Alice wins exactly when|c1 - c2| > 2.
Why it works
Starting with a residue-1 stone forces the sequence 1, 1, 2, 1, 2, … to avoid a multiple of 3, and starting with a 2 mirrors it — so Alice needs at least one of each to get a viable opening. An even c0 leaves the parity of the alternation untouched. An odd c0 hands the effective first move to the opponent, and Alice can only survive by exhausting one residue class far enough ahead of the other, which is exactly the gap of more than 2.
Complexity
- Time —
O(n) - Space —
O(1)
Pitfalls
- Simulating the game is exponential; only the three counts matter.
- The
c0parity flips which player is under pressure — swapping the two branches inverts every answer. - The threshold in the odd case is strictly greater than 2, not at least 2.
Reference solution
Python
from typing import List
def stoneGameIX(stones: List[int]) -> bool:
c = [0, 0, 0]
for x in stones:
c[x % 3] += 1
if c[0] % 2 == 0:
return c[1] >= 1 and c[2] >= 1
return abs(c[1] - c[2]) > 2JavaScript
var stoneGameIX = function(stones) {
var c = [0, 0, 0];
for (var i = 0; i < stones.length; i++) c[stones[i] % 3]++;
if (c[0] % 2 === 0) return c[1] >= 1 && c[2] >= 1;
return Math.abs(c[1] - c[2]) > 2;
};Also on the editorial tab: C, C#, C++, Go, Java, Kotlin, PHP, Ruby, Rust, Swift, TypeScript.