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 take turns playing a game, with Alice starting first.
There are n stones in a pile. On each player's turn, they can remove a stone from the pile and receive points based on the stone's value. Alice and Bob may value the stones differently.
You are given two integer arrays of length n, aliceValues and bobValues. Each aliceValues[i] and bobValues[i] represents how Alice and Bob, respectively, value the ith stone.
The winner is the person with the most points after all the stones are chosen. If both players have the same amount of points, the game results in a draw. Both players will play optimally. Both players know the other's values.
Determine the result of the game, and:
1.-1.0.Example 1:
Input: aliceValues = [1,3], bobValues = [2,1] Output: 1 Explanation: If Alice takes stone 1 (0-indexed) first, Alice will receive 3 points. Bob can only choose stone 0, and will only receive 2 points. Alice wins.
Example 2:
Input: aliceValues = [1,2], bobValues = [3,1] Output: 0 Explanation: If Alice takes stone 0, and Bob takes stone 1, they will both have 1 point. Draw.
Example 3:
Input: aliceValues = [2,4,3], bobValues = [1,6,7] Output: -1 Explanation: Regardless of how Alice plays, Bob will be able to have more points than Alice. For example, if Alice takes stone 1, Bob can take stone 2, and Alice takes stone 0, Alice will have 6 points to Bob's 7. Bob wins.
Constraints:
n == aliceValues.length == bobValues.length1 <= n <= 1051 <= aliceValues[i], bobValues[i] <= 100Problem summary: Alice and Bob take turns playing a game, with Alice starting first. There are n stones in a pile. On each player's turn, they can remove a stone from the pile and receive points based on the stone's value. Alice and Bob may value the stones differently. You are given two integer arrays of length n, aliceValues and bobValues. Each aliceValues[i] and bobValues[i] represents how Alice and Bob, respectively, value the ith stone. The winner is the person with the most points after all the stones are chosen. If both players have the same amount of points, the game results in a draw. Both players will play optimally. Both players know the other's values. Determine the result of the game, and: If Alice wins, return 1. If Bob wins, return -1. If the game results in a draw, return 0.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Math · Greedy
[1,3] [2,1]
[1,2] [3,1]
[2,4,3] [1,6,7]
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 #1686: Stone Game VI
class Solution {
public int stoneGameVI(int[] aliceValues, int[] bobValues) {
int n = aliceValues.length;
int[][] vals = new int[n][0];
for (int i = 0; i < n; ++i) {
vals[i] = new int[] {aliceValues[i] + bobValues[i], i};
}
Arrays.sort(vals, (a, b) -> b[0] - a[0]);
int a = 0, b = 0;
for (int k = 0; k < n; ++k) {
int i = vals[k][1];
if (k % 2 == 0) {
a += aliceValues[i];
} else {
b += bobValues[i];
}
}
if (a == b) {
return 0;
}
return a > b ? 1 : -1;
}
}
// Accepted solution for LeetCode #1686: Stone Game VI
func stoneGameVI(aliceValues []int, bobValues []int) int {
vals := make([][2]int, len(aliceValues))
for i, a := range aliceValues {
vals[i] = [2]int{a + bobValues[i], i}
}
slices.SortFunc(vals, func(a, b [2]int) int { return b[0] - a[0] })
a, b := 0, 0
for k, v := range vals {
i := v[1]
if k%2 == 0 {
a += aliceValues[i]
} else {
b += bobValues[i]
}
}
if a > b {
return 1
}
if a < b {
return -1
}
return 0
}
# Accepted solution for LeetCode #1686: Stone Game VI
class Solution:
def stoneGameVI(self, aliceValues: List[int], bobValues: List[int]) -> int:
vals = [(a + b, i) for i, (a, b) in enumerate(zip(aliceValues, bobValues))]
vals.sort(reverse=True)
a = sum(aliceValues[i] for _, i in vals[::2])
b = sum(bobValues[i] for _, i in vals[1::2])
if a > b:
return 1
if a < b:
return -1
return 0
// Accepted solution for LeetCode #1686: Stone Game VI
struct Solution;
use std::cmp::Ordering::*;
impl Solution {
fn stone_game_vi(alice_values: Vec<i32>, bob_values: Vec<i32>) -> i32 {
let n = alice_values.len();
let mut sums = vec![];
for i in 0..n {
sums.push((
alice_values[i] + bob_values[i],
alice_values[i],
bob_values[i],
));
}
sums.sort_unstable();
let mut sum_a = 0;
let mut sum_b = 0;
let mut turn = 0;
while let Some((_, a, b)) = sums.pop() {
if turn % 2 == 0 {
sum_a += a;
} else {
sum_b += b;
}
turn += 1;
}
match sum_a.cmp(&sum_b) {
Greater => 1,
Less => -1,
Equal => 0,
}
}
}
#[test]
fn test() {
let alice_values = vec![1, 3];
let bob_values = vec![2, 1];
let res = 1;
assert_eq!(Solution::stone_game_vi(alice_values, bob_values), res);
let alice_values = vec![1, 2];
let bob_values = vec![3, 1];
let res = 0;
assert_eq!(Solution::stone_game_vi(alice_values, bob_values), res);
let alice_values = vec![2, 4, 3];
let bob_values = vec![1, 6, 7];
let res = -1;
assert_eq!(Solution::stone_game_vi(alice_values, bob_values), res);
}
// Accepted solution for LeetCode #1686: Stone Game VI
function stoneGameVI(aliceValues: number[], bobValues: number[]): number {
const n = aliceValues.length;
const vals: number[][] = [];
for (let i = 0; i < n; ++i) {
vals.push([aliceValues[i] + bobValues[i], i]);
}
vals.sort((a, b) => b[0] - a[0]);
let [a, b] = [0, 0];
for (let k = 0; k < n; ++k) {
const i = vals[k][1];
if (k % 2 == 0) {
a += aliceValues[i];
} else {
b += bobValues[i];
}
}
if (a === b) {
return 0;
}
return a > b ? 1 : -1;
}
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.