Talentd
FleetCode
Make and follow sheets.Sign in

Stone Game III solution and explanation

HardArrayDynamic ProgrammingGame TheoryMath7 min read68.0% acceptanceUpdated 9 Apr 2026
Leetcode 1406. Stone Game IIIFraz · 21:05 · 17K viewsWatch on YouTube
9 more videos on this problem
  1. Leetcode 1406. Stone Game IIIFraz · 21:05 · 17K views
  2. Stone Game III - Leetcode 1406 - PythonNeetCodeIO · 14:49 · 12K views
  3. Stone Game III | Basic to Optimal | EASIEST Explanation | META, GOOGLE | Leetcode-1406 | Live CodecodestorywithMIK · 30:34 · 8K views
  4. Stone Game III || Recursion - Memo - Bottom Up - Optimized || Dynamic Programming || Leetcode 1406Aryan Mittal · 19:10 · 3K views
  5. Stone Game III: Leetcode 1406Tony Teaches · 19:31 · 1K views
  6. LeetCode 1406. Stone Game IIIHappy Coding · 18:25 · 1K views
  7. [Eng] Leetcode | 1406. Stone Game IIICyCode · 8:26 · 375 views
  8. 1406 || Stone Game III || C++ || Leetcode Daily ChallengeCodeFreaks · 26:13 · 338 views
  9. leetcode 1406. stone game IIIjin's tutorial · 5:30 · 319 views
  10. 1406. Stone Game III | LeetCode | Recursive DP | HARDAthar Mohd · 14:46 · 302 views

The problem

Alice and Bob continue their games with piles of stones. There are several stones arranged in a row, and each stone has an associated value which is an integer given in the array stoneValue.

Alice and Bob take turns, with Alice starting first. On each player's turn, that player can take 1, 2, or 3 stones from the first remaining stones in the row.

The score of each player is the sum of the values of the stones taken. The score of each player is 0 initially.

The objective of the game is to end with the highest score, and the winner is the player with the highest score and there could be a tie. The game continues until all the stones have been taken.

Assume Alice and Bob play optimally.

Return "Alice" if Alice will win, "Bob" if Bob will win, or "Tie" if they will end the game with the same score.

Example 1:

Input: stoneValue = [1,2,3,7]
Output: "Bob"
Explanation: Alice will always lose. Her best move will be to take three piles and the score become 6. Now the score of Bob is 7 and Bob wins.

Example 2:

Input: stoneValue = [1,2,3,-9]
Output: "Alice"
Explanation: Alice must choose all the three piles at the first move to win and leave Bob with negative score.
If Alice chooses one pile her score will be 1 and the next move Bob's score becomes 5. In the next move, Alice will take the pile with value = -9 and lose.
If Alice chooses two piles her score will be 3 and the next move Bob's score becomes 3. In the next move, Alice will take the pile with value = -9 and also lose.
Remember that both play optimally so here Alice will choose the scenario that makes her win.

Example 3:

Input: stoneValue = [1,2,3,6]
Output: "Tie"
Explanation: Alice cannot win this game. She can end the game in a draw if she decided to choose all the first three piles, otherwise she will lose.

Constraints:

  • 1 <= stoneValue.length <= 5 * 104
  • -1000 <= stoneValue[i] <= 1000

Approach overview

Problem Overview: You receive an integer array stoneValue. Alice and Bob take turns picking 1 to 3 stones from the start of the array. Each player adds the picked values to their score and both play optimally. The task is to determine whether Alice wins, Bob wins, or the game ends in a tie.

Approach 1: Naive Recursion (Exponential Time)

The most direct idea is to simulate every possible move sequence. From index i, a player can take 1, 2, or 3 stones and recursively evaluate the opponent’s best response. The score difference is computed as current_sum - opponent_best. This models the game as a zero‑sum decision tree. Without caching, the recursion repeatedly recomputes the same states, leading to O(3^n) time and O(n) recursion stack space. This approach demonstrates the game-theory formulation but becomes infeasible even for moderate input sizes.

Approach 2: Recursive Memoization (O(n) time, O(n) space)

The key observation is that the game state depends only on the starting index of the remaining stones. Cache the best score difference for each index using memoization. For position i, iterate over taking 1–3 stones, maintain a running sum, and compute sum - dfs(i + k). Store the maximum result in a memo table so repeated states are reused. This converts the exponential recursion into linear dynamic programming. Each index is solved once, and each state checks at most three options. Time complexity becomes O(n) and space complexity O(n) for the memo plus recursion stack. This approach clearly expresses the optimal-play logic and maps directly to problems in Game Theory and Dynamic Programming.

Approach 3: Dynamic Programming with Suffix Evaluation (O(n) time, O(n) space)

An iterative DP removes recursion overhead. Define dp[i] as the maximum score difference the current player can achieve starting from index i. Traverse the array from right to left. At each position, try taking 1–3 stones, track the running sum, and update dp[i] = max(sum - dp[i+k]). This works because dp[i+k] already represents the opponent’s optimal advantage from the next position. The recurrence captures the competitive nature of the game while avoiding repeated computation. The algorithm processes each index once with at most three transitions, giving O(n) time and O(n) space. Since the input is a simple Array, the DP array is the only extra structure required.

Recommended for interviews: Interviewers expect the dynamic programming formulation. Start by explaining the recursive game-state definition and score difference idea. That demonstrates understanding of optimal play. Then transition to memoization or bottom-up DP to reach the O(n) solution. The suffix DP version is typically preferred in production code because it avoids recursion depth issues and is easier to reason about.

Approach 1: Dynamic Programming with Suffix Evaluation

This approach involves using dynamic programming to evaluate possible outcomes from the end of the stone array to the beginning. This allows us to make optimal decisions at each step because we know the best scores for the rest of the game. The idea is to calculate the maximum score difference Alice can enforce using a suffix-based strategy.

def stoneGameIII(stoneValue):
    n = len(stoneValue)
    dp = [float('-inf')] * (n + 1)
    dp[n] = 0

    for i in range(n - 1, -1, -1):
        take = 0
        for k in range(3):
            if i + k < n:
                take += stoneValue[i + k]
                dp[i] = max(dp[i], take - dp[i + k + 1])

    if dp[0] > 0:
        return 'Alice'
    elif dp[0] < 0:
        return 'Bob'
    else:
        return 'Tie'
public class StoneGameIII {
    public String stoneGameIII(int[] stoneValue) {
        int n = stoneValue.length;
        int[] dp = new int[n + 1];
        dp[n] = 0;  // Game over condition

        for (int i = n - 1; i >= 0; i--) {
            int take = 0;
            dp[i] = Integer.MIN_VALUE;
            for (int k = 0; k < 3 && i + k < n; k++) {
                take += stoneValue[i + k];
                dp[i] = Math.max(dp[i], take - dp[i + k + 1]);
            }
        }

        if (dp[0] > 0) return "Alice";
        else if (dp[0] < 0) return "Bob";
        else return "Tie";
    }
}
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

string stoneGameIII(vector<int>& stoneValue) {
    int n = stoneValue.size();
    vector<int> dp(n + 1, INT_MIN);
    dp[n] = 0;
    
    for (int i = n - 1; i >= 0; --i) {
        int take = 0;
        for (int k = 0; k < 3 && i + k < n; ++k) {
            take += stoneValue[i + k];
            dp[i] = max(dp[i], take - dp[i + k + 1]);
        }
    }
    
    if (dp[0] > 0) return "Alice";
    else if (dp[0] < 0) return "Bob";
    else return "Tie";
}
var stoneGameIII = function(stoneValue) {
    const n = stoneValue.length;
    const dp = new Array(n + 1).fill(Number.MIN_SAFE_INTEGER);
    dp[n] = 0;

    for (let i = n - 1; i >= 0; i--) {
        let take = 0;
        for (let k = 0; k < 3 && (i + k) < n; k++) {
            take += stoneValue[i + k];
            dp[i] = Math.max(dp[i], take - dp[i + k + 1]);
        }
    }

    return dp[0] > 0 ? "Alice" : dp[0] < 0 ? "Bob" : "Tie";
};
#include <stdio.h>
#include <string.h>

int stoneGameIII(int* stoneValue, int stoneValueSize) {
    int dp[stoneValueSize + 1];
    memset(dp, -1, sizeof(dp));
    
    dp[stoneValueSize] = 0; // Base case
    
    for (int i = stoneValueSize - 1; i >= 0; --i) {
        int take = 0;
        dp[i] = -1001; // A very small number to ensure it gets maximized
        for (int k = 0; k < 3 && i + k < stoneValueSize; ++k) {
            take += stoneValue[i + k];
            dp[i] = fmax(dp[i], take - dp[i + k + 1]);
        }
    }
    
    if (dp[0] > 0) return "Alice";
    else if (dp[0] < 0) return "Bob";
    else return "Tie";
}
public class Solution {
    public string StoneGameIII(int[] stoneValue) {
        int n = stoneValue.Length;
        int[] dp = new int[n + 1];
        dp[n] = 0;

        for (int i = n - 1; i >= 0; i--) {
            int take = 0;
            dp[i] = int.MinValue;
            for (int k = 0; k < 3 && i + k < n; k++) {
                take += stoneValue[i + k];
                dp[i] = Math.Max(dp[i], take - dp[i + k + 1]);
            }
        }

        if (dp[0] > 0) return "Alice";
        else if (dp[0] < 0) return "Bob";
        else return "Tie";
    }
}

In this Python solution, a list of size n + 1 is used for the DP table, initialized to negative infinity. The function processes the list backward, computing the best possible outcome by evaluating 1 to 3 stone picks.

Complexity

Time Complexity: O(n), since we are processing each stone index once.
Space Complexity: O(n), we use a list of size n+1 for storing results of dynamic states.

Try this approach in the editor

Approach 2: Recursive Memoization

This approach leverages the recursive computation of outcomes with memoization. We recursively compute the score differences at each step, caching the results to avoid redundant calculations. At each stone index, the player's optimal score is determined by considering 1 to 3 stone choices.

def stoneGameIII(stoneValue):
    from functools import lru_cache

    n = len(stoneValue)

    @lru_cache(None)
    def dp(i):
        if i >= n:
            return 0
        max_diff = float('-inf')
        take = 0
        for k in range(3):
            if i + k < n:
                take += stoneValue[i + k]
                max_diff = max(max_diff, take - dp(i + k + 1))
        return max_diff

    result = dp(0)
    if result > 0:
        return 'Alice'
    elif result < 0:
        return 'Bob'
    else:
        return 'Tie'

The Python solution employs a memoization decorator to cache previously computed results, optimizing recursive calls. This avoids recalculating results for subproblems, ensuring efficiency. Each call makes decisions based on potential stone selections and returns the best achievable score differential for Alice.

Complexity

Time Complexity: O(n), due to computation of score differences for unique indices once per index.
Space Complexity: O(n), from the recursive call stack and memoization cache storing outcomes for each state.

Try this approach in the editor

Approach 3: Memoization Search

We design a function dfs(i), which represents the maximum score difference that the current player can obtain when playing the game in the range [i, n). If dfs(0) > 0, it means that the first player Alice can win; if dfs(0) < 0, it means that the second player Bob can win; otherwise, it means that the two players tie.

The execution logic of the function dfs(i) is as follows:

  • If i geq n, it means that there are no stones to take now, so we can directly return 0;
  • Otherwise, we enumerate that the current player takes the first j+1 piles of stones, where j \in {0, 1, 2}. Then the score difference that the other player can get in the next round is dfs(i + j + 1), so the score difference that the current player can get is sum_{k=i}^{i+j} stoneValue[k] - dfs(i + j + 1). We want to maximize the score difference of the current player, so we can use the max function to get the maximum score difference, that is:

$ dfs(i) = max_{j \in {0, 1, 2}} \left{sum_{k=i}^{i+j} stoneValue[k] - dfs(i + j + 1)\right}

To prevent repeated calculations, we can use memoization search.

The time complexity is O(n), and the space complexity is O(n). Where n$ is the number of piles of stones.

function stoneGameIII(stoneValue: number[]): string {
    const n = stoneValue.length;
    const inf = 1 << 30;
    const f: number[] = new Array(n).fill(inf);
    const dfs = (i: number): number => {
        if (i >= n) {
            return 0;
        }
        if (f[i] !== inf) {
            return f[i];
        }
        let ans = -inf;
        let s = 0;
        for (let j = 0; j < 3 && i + j < n; ++j) {
            s += stoneValue[i + j];
            ans = Math.max(ans, s - dfs(i + j + 1));
        }
        return (f[i] = ans);
    };
    const ans = dfs(0);
    if (ans === 0) {
        return 'Tie';
    }
    return ans > 0 ? 'Alice' : 'Bob';
}
func stoneGameIII(stoneValue []int) string {
	n := len(stoneValue)
	f := make([]int, n)
	const inf = 1 << 30
	for i := range f {
		f[i] = inf
	}
	var dfs func(int) int
	dfs = func(i int) int {
		if i >= n {
			return 0
		}
		if f[i] != inf {
			return f[i]
		}
		ans, s := -(1 << 30), 0
		for j := 0; j < 3 && i+j < n; j++ {
			s += stoneValue[i+j]
			ans = max(ans, s-dfs(i+j+1))
		}
		f[i] = ans
		return ans
	}
	ans := dfs(0)
	if ans == 0 {
		return "Tie"
	}
	if ans > 0 {
		return "Alice"
	}
	return "Bob"
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Dynamic Programming with Suffix Evaluation

Time Complexity: O(n), since we are processing each stone index once.
Space Complexity: O(n), we use a list of size n+1 for storing results of dynamic states.

Recursive Memoization

Time Complexity: O(n), due to computation of score differences for unique indices once per index.
Space Complexity: O(n), from the recursive call stack and memoization cache storing outcomes for each state.

Memoization Search–

Complexity analysis

ApproachTimeSpaceWhen to Use
Naive RecursionO(3^n)O(n)Conceptual understanding of the game tree and optimal-play reasoning
Recursive MemoizationO(n)O(n)Clear top-down implementation of the optimal strategy with caching
Dynamic Programming with Suffix EvaluationO(n)O(n)Interview-ready and production-friendly solution without recursion

Frequently asked questions

Is Stone Game III easy or hard?

Stone Game III is classified as Hard because it combines dynamic programming with optimal game strategy. The challenge lies in modeling the state as a score difference and recognizing the recurrence dp[i] = max(sum − dp[i+k]).

Stone Game III Python/Java solution

Python and Java solutions typically implement either top-down memoization or bottom-up dynamic programming. Both compute the maximum score difference for each index while considering the next three possible moves, achieving O(n) time complexity.

How to solve Stone Game III in O(n)?

Use dynamic programming where dp[i] represents the best score difference from index i. Traverse the array from right to left and compute dp[i] = max(sum_of_taken_stones − dp[i+k]) for k = 1 to 3. Each state is computed once, resulting in O(n) time.

What is the best approach for Stone Game III?

Dynamic programming with suffix evaluation is the most efficient approach. Define dp[i] as the maximum score difference a player can achieve starting at index i. By trying 1–3 stones and subtracting the opponent’s optimal result (dp[i+k]), the algorithm determines the best move in O(n) time.

Is Stone Game III asked at Google/Amazon/Meta?

Stone Game III belongs to the dynamic programming and game theory category commonly asked by companies like Google, Amazon, and Meta. Interviewers use it to test optimal decision modeling, state transitions, and DP optimization skills.

What data structure is used in Stone Game III?

The main structure is a dynamic programming array or memoization map indexed by the stone position. The input itself is a simple array, and the DP structure stores the best score difference achievable from each index.

What is the time complexity of Stone Game III?

The optimal solution runs in O(n) time because each index in the array is processed once and evaluates at most three transitions. Space complexity is O(n) for the DP array or memo table used to store intermediate results.

Comments

Now write it yourselfClose this page and solve Stone Game III in the editor, without looking.
Practise Stone Game III