Bird
Raised Fist0
Interview Prepdp-grid-intervalsmediumAmazonGoogle

Stone Game (Optimal Strategy)

Choose your preparation mode4 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
📋
Problem

Imagine two players taking turns to pick stones from either end of a row of piles, each trying to maximize their own total stones collected. How can one determine if the first player can always win assuming both play optimally?

Given an array piles where piles[i] represents the number of stones in the i-th pile, two players (Alex and Lee) take turns picking a pile from either the start or the end of the row. Both players play optimally. Return true if Alex can win (get more stones than Lee), otherwise false.

2 ≤ piles.length ≤ 500piles.length is even1 ≤ piles[i] ≤ 500
Edge cases: All piles have the same number of stones → Alex always wins or tiesOnly two piles → Alex picks the larger pile and winsPiles with increasing values → Alex picks optimally to maximize gain
</>
IDE
def stoneGame(piles: list[int]) -> bool:public boolean stoneGame(int[] piles)bool stoneGame(vector<int>& piles)function stoneGame(piles)
def stoneGame(piles):
    # Write your solution here
    pass
class Solution {
    public boolean stoneGame(int[] piles) {
        // Write your solution here
        return false;
    }
}
#include <vector>
using namespace std;

bool stoneGame(vector<int>& piles) {
    // Write your solution here
    return false;
}
function stoneGame(piles) {
    // Write your solution here
}
Coming soon
0/9
Common Bugs to Avoid
Wrong: falseUsing a greedy approach that picks the largest pile first without considering future moves.Implement interval DP with dp[i][j] = max(piles[i] - dp[i+1][j], piles[j] - dp[i][j-1]) to consider all subproblems.
Wrong: falseIncorrect handling of base cases, especially intervals of length 1 or 2.Initialize dp[i][i] = piles[i] and handle intervals of length 2 explicitly in DP.
Wrong: falseOff-by-one errors in DP indices causing incorrect subproblem results.Carefully manage dp indices and ensure loops and recursion boundaries are correct.
Wrong: falseAllowing multiple picks per turn (unbounded) instead of exactly one pile per turn.Restrict picks to one pile per turn by defining dp over intervals and alternating turns.
Wrong: TLEUsing pure recursion without memoization leading to exponential time complexity.Implement memoization or bottom-up DP to achieve O(n^2) time complexity.
Test Cases
t1_01basic
Input{"piles":[5,3,4,5]}
Expectedtrue

Alex picks 5 from start, Lee picks 5 from end, Alex picks 4, Lee picks 3. Alex total = 9, Lee total = 8, so Alex wins.

t1_02basic
Input{"piles":[3,9,1,2]}
Expectedtrue

Alex picks 3 or 2 first, but optimal play leads Alex to win with total stones more than Lee.

t2_01edge
Input{"piles":[10,10,10,10]}
Expectedfalse

All piles have the same stones; Alex can always tie or win by picking first.

t2_02edge
Input{"piles":[7,3]}
Expectedtrue

Only two piles; Alex picks the larger pile (7) and wins immediately.

t2_03edge
Input{"piles":[1,2,3,4,5,6]}
Expectedtrue

Piles with increasing values; Alex picks optimally to maximize gain and wins.

t3_01corner
Input{"piles":[1,100,1,100,1,100]}
Expectedtrue

Greedy trap: picking the largest pile first is not always optimal; interval DP needed.

t3_02corner
Input{"piles":[500,1,500,1,500,1]}
Expectedtrue

Off-by-one error test: DP indices must be carefully managed to avoid incorrect subproblem results.

t3_03corner
Input{"piles":[2,2,2,2,2,2,2,2]}
Expectedfalse

Confusion between 0/1 and unbounded picks: only one pile can be taken per turn.

t4_01performance
Input{"piles":[500,499,498,497,496,495,494,493,492,491,490,489,488,487,486,485,484,483,482,481,480,479,478,477,476,475,474,473,472,471,470,469,468,467,466,465,464,463,462,461,460,459,458,457,456,455,454,453,452,451,450,449,448,447,446,445,444,443,442,441,440,439,438,437,436,435,434,433,432,431,430,429,428,427,426,425,424,423,422,421,420,419,418,417,416,415,414,413,412,411,410,409,408,407,406,405,404,403,402,401]}
⏱ Performance - must finish in 2000ms

n=100, O(n^2) DP must complete within 2 seconds.

Practice

(1/5)
1. Given the following code for finding the cheapest flight within K stops, what is the returned value for the input below? Input: n = 3 flights = [[0,1,100],[1,2,100],[0,2,500]] src = 0 dst = 2 K = 1
def findCheapestPrice(n, flights, src, dst, K):
    INF = float('inf')
    prev = [INF] * n
    prev[src] = 0
    for _ in range(K + 1):
        curr = prev[:]
        for u, v, w in flights:
            if prev[u] != INF:
                curr[v] = min(curr[v], prev[u] + w)
        prev = curr
    return prev[dst] if prev[dst] != INF else -1

print(findCheapestPrice(n, flights, src, dst, K))
easy
A. 500
B. 200
C. -1
D. 100

Solution

  1. Step 1: Trace dp arrays for each iteration

    Initially prev = [0, inf, inf]. After first iteration (0 stops), curr updates cost to city 1 as 100 and city 2 as 500. After second iteration (1 stop), curr updates city 2 cost to min(500, 100 + 100) = 200.
  2. Step 2: Return final cost for destination

    prev[2] after K+1=2 iterations is 200, which is the cheapest cost with at most 1 stop.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    DP updates costs correctly over K+1 iterations [OK]
Hint: DP updates cost over K+1 iterations [OK]
Common Mistakes:
  • Returning direct edge cost ignoring stops
  • Off-by-one in iteration count
  • Confusing curr and prev arrays
2. What is the time complexity of the space-optimized bottom-up DP solution for the Cheapest Flights Within K Stops problem, given n cities, E flights, and maximum K stops?
medium
A. O(K * E) because each iteration relaxes all edges up to K+1 times
B. O(n^3) due to nested loops over cities and stops
C. O(E * log n) similar to Dijkstra's algorithm
D. O(n * K^2) due to dynamic programming over stops and cities

Solution

  1. Step 1: Identify loops in the algorithm

    The outer loop runs K+1 times, and the inner loop iterates over all E flights to relax edges.
  2. Step 2: Calculate total complexity

    Each iteration processes E edges, so total time is O(K * E). No nested loops over n^2 or log factors appear.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Algorithm iterates over edges K+1 times [OK]
Hint: Outer loop K+1 times, inner loop over E edges [OK]
Common Mistakes:
  • Confusing E with n^2
  • Assuming Dijkstra complexity
  • Counting recursion stack space
3. The following code attempts to solve the Triangle minimum path sum problem using bottom-up DP. Identify the line that contains a subtle bug causing incorrect results on some inputs.
medium
A. for i in range(len(triangle) - 2, -1, -1):
B. dp[j] = triangle[i][j] + min(dp[j + 1], dp[j])
C. dp = triangle[-1][:]
D. return dp[0]

Solution

  1. Step 1: Examine dp update line

    The original code has dp[j] = triangle[i][j] + min(dp[j], dp[j + 1]). The buggy code swaps the min arguments to min(dp[j + 1], dp[j]) which is harmless since min is commutative.
  2. Step 2: Check for index out of bounds risk

    Accessing dp[j + 1] is safe because dp length is one more than current row length, so no out-of-bounds here.
  3. Step 3: Identify subtle bug

    The subtle bug is that dp is updated in place from left to right, which can cause dp[j + 1] to be already updated when used in min, leading to incorrect results.
  4. Step 4: Explanation of bug

    Because dp is updated from left to right, dp[j + 1] may have been updated in the current iteration, so min(dp[j], dp[j + 1]) uses a mixed state of dp values.
  5. Step 5: Correct fix

    To fix, update dp from right to left so dp[j + 1] is not yet updated when used.
  6. Final Answer:

    Option B -> Option B
  7. Quick Check:

    Updating dp in wrong order causes subtle bugs [OK]
Hint: Bug usually in dp update line with min or indexing [OK]
Common Mistakes:
  • Swapping min arguments (harmless but suspicious)
  • Index out of bounds on dp[j+1]
  • Updating dp in wrong order causing overwritten values
4. The following code attempts to compute the number of unique paths in an m x n grid using a space-optimized DP approach:
def uniquePaths(m, n):
    dp = [1] * n
    for i in range(1, m):
        for j in range(1, n):
            dp[j] = dp[j] + dp[j]
    return dp[-1]
What is the bug in this code?
medium
A. Line 3 should start loop from 0 instead of 1
B. Line 4 incorrectly doubles dp[j] instead of adding dp[j-1]
C. Line 5 should return dp[0] instead of dp[-1]
D. Line 2 initializes dp with wrong size

Solution

  1. Step 1: Analyze inner loop update

    Line 4 updates dp[j] by adding dp[j] to itself, doubling the value instead of adding dp[j-1].
  2. Step 2: Identify correct update

    The correct update is dp[j] += dp[j - 1] to accumulate paths from left and top cells.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Doubling dp[j] breaks path count logic -> bug at line 4 [OK]
Hint: Check dp update uses dp[j-1], not dp[j] twice [OK]
Common Mistakes:
  • Using dp[j] + dp[j] instead of dp[j] + dp[j-1]
  • Off-by-one errors in loops
5. Examine the following buggy code snippet from the Zuma Game solution. Which line contains the subtle bug that causes incorrect minimal moves calculation?
medium
A. Line with 'new_s = s[:i] + s[j:] # BUG: missing recursive removal'
B. Line with 'balls_needed = 3 - (j - i)'
C. Line with 'hand_count[s[i]] -= balls_needed'
D. Line with 'if temp != -1:'

Solution

  1. Step 1: Identify role of remove_consecutive

    After insertion and removal, consecutive balls must be recursively removed to handle chain reactions.
  2. Step 2: Locate missing recursive removal

    The line creating new_s omits calling remove_consecutive, so chain reactions are not processed, leading to incorrect board states and minimal moves.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Missing recursive removal causes wrong minimal moves [OK]
Hint: Missing recursive removal breaks chain reaction logic [OK]
Common Mistakes:
  • Forgetting to call remove_consecutive after insertion
  • Incorrectly adjusting hand counts
  • Miscomputing balls needed for removal