Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
Alice and Bob continue their games with stones. There is a row of n stones, and each stone has an associated value. You are given an integer array stones, where stones[i] is the value of the ith stone.
Alice and Bob take turns, with Alice starting first. On each turn, the player may remove any stone from stones. The player who removes a stone loses if the sum of the values of all removed stones is divisible by 3. Bob will win automatically if there are no remaining stones (even if it is Alice's turn).
Assuming both players play optimally, return true if Alice wins and false if Bob wins.
Example 1:
Input: stones = [2,1] Output: true Explanation: The game will be played as follows: - Turn 1: Alice can remove either stone. - Turn 2: Bob removes the remaining stone. The sum of the removed stones is 1 + 2 = 3 and is divisible by 3. Therefore, Bob loses and Alice wins the game.
Example 2:
Input: stones = [2] Output: false Explanation: Alice will remove the only stone, and the sum of the values on the removed stones is 2. Since all the stones are removed and the sum of values is not divisible by 3, Bob wins the game.
Example 3:
Input: stones = [5,1,2,4,3] Output: false Explanation: Bob will always win. One possible way for Bob to win is shown below: - Turn 1: Alice can remove the second stone with value 1. Sum of removed stones = 1. - Turn 2: Bob removes the fifth stone with value 3. Sum of removed stones = 1 + 3 = 4. - Turn 3: Alices removes the fourth stone with value 4. Sum of removed stones = 1 + 3 + 4 = 8. - Turn 4: Bob removes the third stone with value 2. Sum of removed stones = 1 + 3 + 4 + 2 = 10. - Turn 5: Alice removes the first stone with value 5. Sum of removed stones = 1 + 3 + 4 + 2 + 5 = 15. Alice loses the game because the sum of the removed stones (15) is divisible by 3. Bob wins the game.
Constraints:
1 <= stones.length <= 1051 <= stones[i] <= 104Problem summary: Alice and Bob continue their games with stones. There is a row of n stones, and each stone has an associated value. You are given an integer array stones, where stones[i] is the value of the ith stone. Alice and Bob take turns, with Alice starting first. On each turn, the player may remove any stone from stones. The player who removes a stone loses if the sum of the values of all removed stones is divisible by 3. Bob will win automatically if there are no remaining stones (even if it is Alice's turn). Assuming both players play optimally, return true if Alice wins and false if Bob wins.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Math · Greedy
[2,1]
[2]
[5,1,2,4,3]
stone-game)stone-game-ii)stone-game-iii)stone-game-iv)stone-game-v)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #2029: Stone Game IX
class Solution {
public boolean stoneGameIX(int[] stones) {
int[] c1 = new int[3];
for (int x : stones) {
c1[x % 3]++;
}
int[] c2 = {c1[0], c1[2], c1[1]};
return check(c1) || check(c2);
}
private boolean check(int[] cnt) {
if (--cnt[1] < 0) {
return false;
}
int r = 1 + Math.min(cnt[1], cnt[2]) * 2 + cnt[0];
if (cnt[1] > cnt[2]) {
--cnt[1];
++r;
}
return r % 2 == 1 && cnt[1] != cnt[2];
}
}
// Accepted solution for LeetCode #2029: Stone Game IX
func stoneGameIX(stones []int) bool {
c1 := [3]int{}
for _, x := range stones {
c1[x%3]++
}
c2 := [3]int{c1[0], c1[2], c1[1]}
check := func(cnt [3]int) bool {
if cnt[1] == 0 {
return false
}
cnt[1]--
r := 1 + min(cnt[1], cnt[2])*2 + cnt[0]
if cnt[1] > cnt[2] {
cnt[1]--
r++
}
return r%2 == 1 && cnt[1] != cnt[2]
}
return check(c1) || check(c2)
}
# Accepted solution for LeetCode #2029: Stone Game IX
class Solution:
def stoneGameIX(self, stones: List[int]) -> bool:
def check(cnt: List[int]) -> bool:
if cnt[1] == 0:
return False
cnt[1] -= 1
r = 1 + min(cnt[1], cnt[2]) * 2 + cnt[0]
if cnt[1] > cnt[2]:
cnt[1] -= 1
r += 1
return r % 2 == 1 and cnt[1] != cnt[2]
c1 = [0] * 3
for x in stones:
c1[x % 3] += 1
c2 = [c1[0], c1[2], c1[1]]
return check(c1) or check(c2)
// Accepted solution for LeetCode #2029: Stone Game IX
/**
* [2029] Stone Game IX
*
* Alice and Bob continue their games with stones. There is a row of n stones, and each stone has an associated value. You are given an integer array stones, where stones[i] is the value of the i^th stone.
* Alice and Bob take turns, with Alice starting first. On each turn, the player may remove any stone from stones. The player who removes a stone loses if the sum of the values of all removed stones is divisible by 3. Bob will win automatically if there are no remaining stones (even if it is Alice's turn).
* Assuming both players play optimally, return true if Alice wins and false if Bob wins.
*
* Example 1:
*
* Input: stones = [2,1]
* Output: true
* Explanation: The game will be played as follows:
* - Turn 1: Alice can remove either stone.
* - Turn 2: Bob removes the remaining stone.
* The sum of the removed stones is 1 + 2 = 3 and is divisible by 3. Therefore, Bob loses and Alice wins the game.
*
* Example 2:
*
* Input: stones = [2]
* Output: false
* Explanation: Alice will remove the only stone, and the sum of the values on the removed stones is 2.
* Since all the stones are removed and the sum of values is not divisible by 3, Bob wins the game.
*
* Example 3:
*
* Input: stones = [5,1,2,4,3]
* Output: false
* Explanation: Bob will always win. One possible way for Bob to win is shown below:
* - Turn 1: Alice can remove the second stone with value 1. Sum of removed stones = 1.
* - Turn 2: Bob removes the fifth stone with value 3. Sum of removed stones = 1 + 3 = 4.
* - Turn 3: Alices removes the fourth stone with value 4. Sum of removed stones = 1 + 3 + 4 = 8.
* - Turn 4: Bob removes the third stone with value 2. Sum of removed stones = 1 + 3 + 4 + 2 = 10.
* - Turn 5: Alice removes the first stone with value 5. Sum of removed stones = 1 + 3 + 4 + 2 + 5 = 15.
* Alice loses the game because the sum of the removed stones (15) is divisible by 3. Bob wins the game.
*
*
* Constraints:
*
* 1 <= stones.length <= 10^5
* 1 <= stones[i] <= 10^4
*
*/
pub struct Solution {}
// problem: https://leetcode.com/problems/stone-game-ix/
// discuss: https://leetcode.com/problems/stone-game-ix/discuss/?currentPage=1&orderBy=most_votes&query=
// submission codes start here
impl Solution {
pub fn stone_game_ix(stones: Vec<i32>) -> bool {
false
}
}
// submission codes end
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[ignore]
fn test_2029_example_1() {
let stones = vec![2, 1];
let result = true;
assert_eq!(Solution::stone_game_ix(stones), result);
}
#[test]
#[ignore]
fn test_2029_example_2() {
let stones = vec![2];
let result = false;
assert_eq!(Solution::stone_game_ix(stones), result);
}
#[test]
#[ignore]
fn test_2029_example_3() {
let stones = vec![5, 1, 2, 4, 3];
let result = false;
assert_eq!(Solution::stone_game_ix(stones), result);
}
}
// Accepted solution for LeetCode #2029: Stone Game IX
function stoneGameIX(stones: number[]): boolean {
const c1: number[] = Array(3).fill(0);
for (const x of stones) {
++c1[x % 3];
}
const c2: number[] = [c1[0], c1[2], c1[1]];
const check = (cnt: number[]): boolean => {
if (--cnt[1] < 0) {
return false;
}
let r = 1 + Math.min(cnt[1], cnt[2]) * 2 + cnt[0];
if (cnt[1] > cnt[2]) {
--cnt[1];
++r;
}
return r % 2 === 1 && cnt[1] !== cnt[2];
};
return check(c1) || check(c2);
}
Use this to step through a reusable interview workflow for this problem.
Try every possible combination of choices. With n items each having two states (include/exclude), the search space is 2ⁿ. Evaluating each combination takes O(n), giving O(n × 2ⁿ). The recursion stack or subset storage uses O(n) space.
Greedy algorithms typically sort the input (O(n log n)) then make a single pass (O(n)). The sort dominates. If the input is already sorted or the greedy choice can be computed without sorting, time drops to O(n). Proving greedy correctness (exchange argument) is harder than the implementation.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Wrong move: Temporary multiplications exceed integer bounds.
Usually fails on: Large inputs wrap around unexpectedly.
Fix: Use wider types, modular arithmetic, or rearranged operations.
Wrong move: Locally optimal choices may fail globally.
Usually fails on: Counterexamples appear on crafted input orderings.
Fix: Verify with exchange argument or monotonic objective before committing.