Stone Removal Game

Last Updated : 30 Oct, 2025

Given an array arr[], where each element represents a pile of stone, two players Player1 and Player2 play a game taking alternating turns. In each turn, a player may take 1, 2, or 3 consecutive piles of stones from the beginning of the remaining array which will be added to there respective score. Considering that both players play optimally, we have to find the result of the game, Player with the highest score.

  • Return 1 -> if player 1 wins the game.
  • Return 2 -> if player 2 wins the game.
  • Return 0 -> if game ends as a tie.

Examples:

Input: arr[] = [1, 2, 3, 7]
Output: 2
Explanation: Player1 will always lose as:
In any scenario, even if player1 choose (1), (1+2) or (1+2+3) as his score
player2 will win by choosing (2+3+7), (3+7) or (7).

Input: arr[] = [4, 2, 3, 7]
Output: 1
Explanation: Player2 will lose as:
player1 can pick (4), (4+2) or (4+2+3) as his score on his first move.
then player2 can pick (2+3+7), (3+7) or (7).
so (4+2+3), picking the first 3 piles of stone is ideal move of player1.

[Naive Approach]: Using basic Recursion

The idea is to use recursion to try out every possible move where a player can pick 1, 2, or 3 piles of stones from the start that are unpicked. At each step, the player chooses the option that gives the best overall score, keeping in mind that the opponent will also play optimally in the next turn. Here we have to calculates the best score difference that the current players can achieve from a given position. In the end finally, based on whether the difference is positive, negative, or zero, we will determine the winner of the game.

Follow the steps to solve the problem:

  • Declare a recursive function, that will calculate the maximum score of Player1 if the game starts at index i.
  • If the value of i ≥ n, return 0.
  • Initialize a variable, say score as INT_MIN, to store the maximum score of Player1
    Picks 1 stone: score = max(score, arr[i] - maxScore(i + 1))
    Picks 2 stones i.e (i + 1 < n): score = max(score, arr[i] + arr[i + 1] - maxScore(i + 2))
    Picks 3 stones i.e (i + 2 < n): score = max(score, arr[i] + arr[i + 1] + arr[i + 2] - maxScore(i + 3))
  • Return the value of the score.
  • Store the value of maxScore(0) in a variable res.
  • return the result according to res.
C++
#include <iostream>
#include <climits>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;

// Function to find the maximum score of Player1
int maximumStonesUtil(vector<int>& arr, int k)
{
    int n = arr.size();
    
    // Base Case
    if (k >= n)
        return 0;

    // Variable to store maximum score
    int ans = INT_MIN;

    // Pick one stone
    ans = max(ans,
              arr[k] - maximumStonesUtil(arr, k + 1));

    // Pick 2 stones
    if (k + 1 < n)
        ans = max(ans,
                  arr[k] + arr[k + 1]
                      - maximumStonesUtil(arr, k + 2));

    // Pick 3 stones
    if (k + 2 < n)
        ans = max(ans,
                  arr[k] + arr[k + 1] + arr[k + 2]
                      - maximumStonesUtil(arr, k + 3));

    // Return the score of the player
    return ans;
}

// Function to find the winner of the game
int maximumStones(vector<int>& arr)
{
    int n = arr.size();

    // Store the result
    int res = maximumStonesUtil(arr, 0);

   // Determine the winner
    if (res > 0)
        return 1;
    else if (res < 0)
        return 2;
    else
        return 0;
}

// Driver Code
int main()
{
    // Given Input
    vector<int> arr = { 1, 2, 3, 7 };

    // Function Call
    cout << maximumStones(arr);

    return 0;
}
Java
public class Main {

    // Function to find the maximum score of Player1
    static int maximumStonesUtil(int[] arr, int k) {
        int n = arr.length;

        // Base Case
        if (k >= n)
            return 0;

        // Variable to store maximum score
        int ans = Integer.MIN_VALUE;

        // Pick one stone
        ans = Math.max(ans, arr[k] - maximumStonesUtil(arr, k + 1));

        // Pick 2 stones
        if (k + 1 < n)
            ans = Math.max(ans, arr[k] + arr[k + 1] 
                                   - maximumStonesUtil(arr, k + 2));

        // Pick 3 stones
        if (k + 2 < n)
            ans = Math.max(ans, arr[k] + arr[k + 1] 
                      + arr[k + 2] - maximumStonesUtil(arr, k + 3));

        // Return the score of the player
        return ans;
    }

    // Function to find the winner of the game
    static int maximumStones(int[] arr) {
        int res = maximumStonesUtil(arr, 0);

        // Determine the winner
        if (res > 0)
            return 1;
        else if (res < 0)
            return 2;
        else
            return 0;
    }

    // Driver Code
    public static void main(String[] args) {
        // Given Input
        int[] arr = {1, 2, 3, 7};

        // Function Call
        System.out.println(maximumStones(arr));
    }
}
Python
# Function to find the maximum score of Player1
def maximumStonesUtil(arr, k):
    n = len(arr)
    
    # Base Case
    if k >= n:
        return 0

    # Variable to store maximum score
    ans = float('-inf')

    # Pick one stone
    ans = max(ans, arr[k] - maximumStonesUtil(arr, k + 1))

    # Pick 2 stones
    if k + 1 < n:
        ans = max(ans, arr[k] + arr[k + 1]
                          - maximumStonesUtil(arr, k + 2))

    # Pick 3 stones
    if k + 2 < n:
        ans = max(ans, arr[k] + arr[k + 1] + arr[k + 2]
                          - maximumStonesUtil(arr, k + 3))

    # Return the score of the player
    return ans


# Function to find the winner of the game
def maximumStones(arr):

    # Store the result
    res = maximumStonesUtil(arr, 0)

    #  Determine the winner
    if res > 0:
        return 1
    elif res < 0:
        return 2
    else:
        return 0


# Driver Code
if __name__ == "__main__":
    # Given Input
    arr = [1, 2, 3, 7]

    # Function Call
    print(maximumStones(arr))
C#
using System;

class Program
{
    // Function to find the maximum score of Player1
    static int MaximumStonesUtil(int[] arr, int k)
    {
        int n = arr.Length;

        // Base Case
        if (k >= n)
            return 0;

        // Variable to store maximum score
        int ans = int.MinValue;

        // Pick one stone
        ans = Math.Max(ans, arr[k] - MaximumStonesUtil(arr, k + 1));

        // Pick 2 stones
        if (k + 1 < n)
            ans = Math.Max(ans, arr[k] + arr[k + 1] 
                                  - MaximumStonesUtil(arr, k + 2));

        // Pick 3 stones
        if (k + 2 < n)
            ans = Math.Max(ans, arr[k] + arr[k + 1] 
                      + arr[k + 2] - MaximumStonesUtil(arr, k + 3));

        // Return the score of the player
        return ans;
    }

    // Function to find the winner of the game
    static int MaximumStones(int[] arr)
    {
        int res = MaximumStonesUtil(arr, 0);

        // Determine the winner
        if (res > 0)
            return 1;
        else if (res < 0)
            return 2;
        else
            return 0;
    }

    // Driver Code
    static void Main()
    {
        // Given Input
        int[] arr = { 1, 2, 3, 7 };

        // Function Call
        Console.WriteLine(MaximumStones(arr));
    }
}
JavaScript
// Function to find the maximum score of Player1
function maximumStonesUtil(arr, k) {
    const n = arr.length;

    // Base Case
    if (k >= n)
        return 0;

    // Variable to store maximum score
    let ans = Number.NEGATIVE_INFINITY;

    // Pick one stone
    ans = Math.max(ans, arr[k] - maximumStonesUtil(arr, k + 1));

    // Pick 2 stones
    if (k + 1 < n)
        ans = Math.max(ans, arr[k] + arr[k + 1] 
                                - maximumStonesUtil(arr, k + 2));

    // Pick 3 stones
    if (k + 2 < n)
        ans = Math.max(ans, arr[k] + arr[k + 1] 
                   + arr[k + 2] - maximumStonesUtil(arr, k + 3));

    // Return the score of the player
    return ans;
}

// Function to find the winner of the game
function maximumStones(arr) {
    const res = maximumStonesUtil(arr, 0);

    // Determine the winner
    if (res > 0)
        return 1;
    else if (res < 0)
        return 2;
    else
        return 0;
}

// Driver Code
const arr = [1, 2, 3, 7];

// Function Call
console.log(maximumStones(arr));

Output
2

Time Complexity: O(3n)
Auxiliary Space: O(n)

[Efficient Approach I]: Using dynamic programming ( top-down approach )

To optimize the above approach, we will be using Dynamic Programming , this problem exhibits both the optimal substructure and overlapping subproblems properties, making it a perfect fit for DP. We will use memoization by creating a dp to store the results of previously computed recursive calls, which helps eliminate redundant calculations and significantly improve efficiency.

C++
#include <iostream>
#include <vector>
#include <climits>
#include <string>
#include <algorithm>
using namespace std;

// Function to find the maximum score of Player 1
int maximumStonesUtil(vector<int>& arr, int k, vector<int>& dp)
{
    int n = arr.size();
    
    // Base Case
    if (k >= n)
        return 0;

    // If the result is already computed, return it
    if (dp[k] != -1)
        return dp[k];

    // Variable to store maximum score
    int ans = INT_MIN;

    // Pick 1 stone
    ans = max(ans, arr[k] - maximumStonesUtil(arr, k + 1, dp));

    // Pick 2 stones
    if (k + 1 < n)
        ans = max(ans, arr[k] + arr[k + 1] 
                          - maximumStonesUtil(arr, k + 2, dp));

    // Pick 3 stones
    if (k + 2 < n)
        ans = max(ans, arr[k] + arr[k + 1] 
              + arr[k + 2] - maximumStonesUtil(arr, k + 3, dp));

    // Store result in dp and return
    dp[k] = ans;
    return dp[k];
}

// Function to find the winner of the game
int maximumStones(vector<int>& arr)
{
    int n = arr.size();

    // Create a 1D DP table
    vector<int> dp(n, -1);

    // Store the result
    int res = maximumStonesUtil(arr, 0, dp);

    // Determine winner
    if (res > 0)
        return 1;
    else if (res < 0)
        return 2;
    else
        return 0;
}

// Driver Code
int main()
{
    vector<int> arr = {1, 2, 3, 7};

    cout << maximumStones(arr);

    return 0;
}
Java
import java.util.*;

public class Main {

    // Function to find the maximum score of Player 1
    static int maximumStonesUtil(int[] arr, int k, int[] dp) {
        int n = arr.length;

        // Base Case
        if (k >= n)
            return 0;

        // If the result is already computed, return it
        if (dp[k] != -1)
            return dp[k];

        // Variable to store maximum score
        int ans = Integer.MIN_VALUE;

        // Pick 1 stone
        ans = Math.max(ans, arr[k] - maximumStonesUtil(arr, k + 1, dp));

        // Pick 2 stones
        if (k + 1 < n)
            ans = Math.max(ans, arr[k] + arr[k + 1]
                                   - maximumStonesUtil(arr, k + 2, dp));

        // Pick 3 stones
        if (k + 2 < n)
            ans = Math.max(ans, arr[k] + arr[k + 1] + arr[k + 2]
                                   - maximumStonesUtil(arr, k + 3, dp));

        // Store result in dp and return
        dp[k] = ans;
        return dp[k];
    }

    // Function to find the winner of the game
    static int maximumStones(int[] arr) {
        int n = arr.length;

        // Create a 1D DP table
        int[] dp = new int[n];
        Arrays.fill(dp, -1);

        // Store the result
        int res = maximumStonesUtil(arr, 0, dp);

        // Determine the winner
        if (res > 0)
            return 1;
        else if (res < 0)
            return 2;
        else
            return 0;
    }

    // Driver Code
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 7};

        System.out.println(maximumStones(arr));
    }
}
Python
def maximumStonesUtil(arr, k, dp):
    n = len(arr)
  
    # Base Case
    if (k >= n):
        return 0
    
    ans = dp[k]
    
    # If the result is already computed, then
    # return the result
    if (ans != -1):
        return ans
        
    # Variable to store maximum score
    ans = -2**31
    
    # Pick one stone
    ans = max( ans, arr[k] - maximumStonesUtil(arr, k + 1, dp))
    
    # Pick 2 stones
    if (k + 1 < n):
        ans = max(ans, arr[k] + arr[k + 1] 
                          - maximumStonesUtil(arr, k + 2, dp))
        
    # Pick 3 stones
    if (k + 2 < n):
        ans = max(ans, arr[k] + arr[k + 1] 
             + arr[k + 2] - maximumStonesUtil(arr, k + 3, dp))
    
    # Return the score of the player
    return ans


# Function to find the winner of the game
def maximumStones(arr):
    n = len(arr)
    
    # Create a 1D table, dp of size N
    dp = [-1] * n
    
    # Store the result
    res = maximumStonesUtil(arr, 0, dp)
    
    # Determine winner
    if (res > 0):
        return 1
    elif (res < 0):
        return 2
    else:
        return 0

# Driver Code

# Given Input
arr = [1, 2, 3, 7] 
n = len(arr)

# Function Call
print(maximumStones(arr))

# This code is contributed by shivani
C#
using System;

class Program
{
    // Function to find the maximum score of Player 1
    static int MaximumStonesUtil(int[] arr, int k, int[] dp)
    {
        int n = arr.Length;

        // Base Case
        if (k >= n)
            return 0;

        // If the result is already computed, return it
        if (dp[k] != -1)
            return dp[k];

        // Variable to store maximum score
        int ans = int.MinValue;

        // Pick 1 stone
        ans = Math.Max(ans, arr[k] - MaximumStonesUtil(arr, k + 1, dp));

        // Pick 2 stones
        if (k + 1 < n)
            ans = Math.Max(ans, arr[k] + arr[k + 1] 
                                   - MaximumStonesUtil(arr, k + 2, dp));

        // Pick 3 stones
        if (k + 2 < n)
            ans = Math.Max(ans, arr[k] + arr[k + 1] 
                      + arr[k + 2] - MaximumStonesUtil(arr, k + 3, dp));

        // Store result in dp and return
        dp[k] = ans;
        return dp[k];
    }

    // Function to find the winner of the game
    static int MaximumStones(int[] arr)
    {
        int n = arr.Length;

        // Create a 1D DP table
        int[] dp = new int[n];
        for (int k = 0; k < n; k++)
            dp[k] = -1;

        // Store the result
        int res = MaximumStonesUtil(arr, 0, dp);

        // Determine winner
        if (res > 0)
            return 1;
        else if (res < 0)
            return 2;
        else
            return 0;
    }

    // Driver Code
    static void Main()
    {
        int[] arr = { 1, 2, 3, 7 };

        Console.WriteLine(MaximumStones(arr));
    }
}
JavaScript
// Function to find the maximum score of Player 1
function maximumStonesUtil(arr, k, dp) {
    const n = arr.length;

    // Base Case
    if (k >= n)
        return 0;

    // If the result is already computed, return it
    if (dp[k] !== -1)
        return dp[k];

    // Variable to store maximum score
    let ans = Number.NEGATIVE_INFINITY;

    // Pick 1 stone
    ans = Math.max(ans, arr[k] - maximumStonesUtil(arr, k + 1, dp));

    // Pick 2 stones
    if (k + 1 < n)
        ans = Math.max(ans, arr[k] + arr[k + 1] 
                               - maximumStonesUtil(arr, k + 2, dp));

    // Pick 3 stones
    if (k + 2 < n)
        ans = Math.max(ans, arr[k] + arr[k + 1] 
                   + arr[k + 2] - maximumStonesUtil(arr, k + 3, dp));

    // Store result in dp and return
    dp[k] = ans;
    return dp[k];
}

// Function to find the winner of the game
function maximumStones(arr) {
    const n = arr.length;

    // Create a 1D DP table
    const dp = new Array(n).fill(-1);

    // Store the result
    const res = maximumStonesUtil(arr, 0, dp);

    // Determine winner
    if (res > 0)
        return 1;
    else if (res < 0)
        return 2;
    else
        return 0;
}

// Driver Code
const arr = [1, 2, 3, 7];
console.log(maximumStones(arr));

Output
2

Time Complexity: O(n)
Auxiliary Space: O(n)

[Efficient Approach II]: Using the DP ( bottom-up approach )

Here a another approach to solving this problem, but using the DP Tabulation (bottom-up) approach as it is showing overlapping subproblems properties, making it a perfect fit for DP.
This approach is better than pervious one as the memoized version uses recursion, which adds extra stack space and function call overhead and in this method we build the DP table iteratively from the end so it runs with the same time complexity but uses less memory and avoids the cost of recursive calls

Steps to solve this problem:

  • Create a DP of size n+3 to store the solution of the subproblems.
  • Initialize the DP  with base cases dp[n] = dp[n+1] = dp[n+2] = 0.
  • Now Iterate over subproblems to get the value of the current problem from the previous computation of subproblems stored in DP
  • return the final result 
C++
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

// Function to find the winner of game
int maximumStones(vector<int>& arr)
{
    int n = arr.size(); 

    // Create a 1D table, dp of size N+3
    vector<int> dp(n + 3, 0);

    // Initialize the table for the last 3 stones
    dp[n] = dp[n + 1] = dp[n + 2] = 0;

    // Calculate the table for the remaining stones in reverse order
    for (int i = n - 1; i >= 0; i--) {
        
        int a = arr[i] - dp[i + 1];
        int b = -1, c = -1;

        if (i + 1 == n) {
            b = arr[i] - dp[i + 2];
            c = arr[i] - dp[i + 3];
        }
        else if (i + 2 == n) {
            c = arr[i] + arr[i + 1] - dp[i + 3];
        }

        if (b == -1)
            b = arr[i] + arr[i + 1] - dp[i + 2];

        if (c == -1)
            c = arr[i] + arr[i + 1] + arr[i + 2] - dp[i + 3];

        dp[i] = max({a, b, c});
    }

    // Determine the winner
    if (dp[0] > 0)
        return 1;
    else if (dp[0] < 0)
        return 2;
    else
        return 0;
}

// Driver Code
int main()
{
    vector<int> arr = {1, 2, 3, 7};

    cout << maximumStones(arr);

    return 0;
}
Java
import java.util.*;

public class Main {

    // Function to find the winner of the game
    public static int maximumStones(int[] arr) {
        int n = arr.length;

        // Create a 1D table, dp of size N+3
        int[] dp = new int[n + 3];

        // Initialize the table for the last 3 stones
        dp[n] = dp[n + 1] = dp[n + 2] = 0;

        // Calculate the table for the remaining stones in reverse order
        for (int i = n - 1; i >= 0; i--) {

            int a = arr[i] - dp[i + 1];
            int b = -1, c = -1;

            if (i + 1 == n) {
                b = arr[i] - dp[i + 2];
                c = arr[i] - dp[i + 3];
            } else if (i + 2 == n) {
                c = arr[i] + arr[i + 1] - dp[i + 3];
            }

            if (b == -1)
                b = arr[i] + arr[i + 1] - dp[i + 2];

            if (c == -1)
                c = arr[i] + arr[i + 1] + arr[i + 2] - dp[i + 3];

            dp[i] = Math.max(a, Math.max(b, c));
        }

        // Determine the winner
        if (dp[0] > 0)
            return 1;
        else if (dp[0] < 0)
            return 2;
        else
            return 0;
    }

    // Driver Code
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 7};

        System.out.println(maximumStones(arr));
    }
}
Python
def maximumStones(arr):
    n = len(arr)

    # Create dp array of size n + 3
    dp = [0] * (n + 3)

    # Initialize the table for the last 3 stones
    dp[n] = dp[n + 1] = dp[n + 2] = 0

    # Calculate the table for the remaining stones in reverse order
    for i in range(n - 1, -1, -1):
        a = arr[i] - dp[i + 1]
        b, c = -1, -1

        if i + 1 == n:
            b = arr[i] - dp[i + 2]
            c = arr[i] - dp[i + 3]
        elif i + 2 == n:
            c = arr[i] + arr[i + 1] - dp[i + 3]

        if b == -1:
            b = arr[i] + arr[i + 1] - dp[i + 2]
        if c == -1:
            c = arr[i] + arr[i + 1] + arr[i + 2] - dp[i + 3]

        dp[i] = max(a, b, c)

    # Determine the winner
    if dp[0] > 0:
        return 1
    elif dp[0] < 0:
        return 2
    else:
        return 0


# Driver Code
arr = [1, 2, 3, 7]
print(maximumStones(arr))
C#
using System;

class Program
{
    // Function to find the winner of the game
    static int MaximumStones(int[] arr)
    {
        int n = arr.Length;

        // Create a 1D table, dp of size N+3
        int[] dp = new int[n + 3];

        // Initialize the table for the last 3 stones
        dp[n] = dp[n + 1] = dp[n + 2] = 0;

        // Calculate the table for the remaining stones in reverse order
        for (int i = n - 1; i >= 0; i--)
        {
            int a = arr[i] - dp[i + 1];
            int b = -1, c = -1;

            if (i + 1 == n)
            {
                b = arr[i] - dp[i + 2];
                c = arr[i] - dp[i + 3];
            }
            else if (i + 2 == n)
            {
                c = arr[i] + arr[i + 1] - dp[i + 3];
            }

            if (b == -1)
                b = arr[i] + arr[i + 1] - dp[i + 2];

            if (c == -1)
                c = arr[i] + arr[i + 1] + arr[i + 2] - dp[i + 3];

            dp[i] = Math.Max(a, Math.Max(b, c));
        }

        // Determine the winner
        if (dp[0] > 0)
            return 1;
        else if (dp[0] < 0)
            return 2;
        else
            return 0;
    }

    // Driver Code
    static void Main()
    {
        int[] arr = { 1, 2, 3, 7 };

        Console.WriteLine(MaximumStones(arr));
    }
}
JavaScript
// Function to find the winner of the game
function maximumStones(arr) {
    const n = arr.length;

    // Create a 1D table, dp of size N+3
    const dp = new Array(n + 3).fill(0);

    // Initialize the table for the last 3 stones
    dp[n] = dp[n + 1] = dp[n + 2] = 0;

    // Calculate the table for the remaining stones in reverse order
    for (let i = n - 1; i >= 0; i--) {
        let a = arr[i] - dp[i + 1];
        let b = -1, c = -1;

        if (i + 1 === n) {
            b = arr[i] - dp[i + 2];
            c = arr[i] - dp[i + 3];
        } 
        else if (i + 2 === n) {
            c = arr[i] + arr[i + 1] - dp[i + 3];
        }

        if (b === -1)
            b = arr[i] + arr[i + 1] - dp[i + 2];

        if (c === -1)
            c = arr[i] + arr[i + 1] + arr[i + 2] - dp[i + 3];

        dp[i] = Math.max(a, b, c);
    }

    // Determine the winner
    if (dp[0] > 0)
        return 1;
    else if (dp[0] < 0)
        return 2;
    else
        return 0;
}

// Driver Code
const arr = [1, 2, 3, 7];
console.log(maximumStones(arr));

Output
2

Time Complexity: O(n)
Auxiliary Space: O(n)


Comment