# Maximize the number of coins collected by X, assuming Y also plays optimally

Two players X and Y are playing a game in which there are pots of gold arranged in a line, each containing some gold coins. They get alternating turns in which the player can pick a pot from one of the ends of the line. The winner is the player who has a higher number of coins at the end. The objective is to maximize the number of coins collected by X, assuming Y also plays optimally. Return the maximum coins X could get while playing the game. Initially, X starts the game.

Examples:

Input: N = 4, Q[] = {8, 15, 3, 7}
Output: 22
Explanation: Player X starts and picks 7. Player Y picks the pot containing 8. Player X picks the pot containing 15. Player Y picks 3. Total coins collected by X = 7 + 15 = 22.

Input:N = 4, A[] = {2, 2, 2, 2}
Output: 4

Approach: This can be solved with the following idea:

Using Dynamic programming as it has an optimum substructure and overlapping subproblems.

Steps involved in the implementation of code:

• Declare a static 1002 x 1002 2D integer array with the name dp.
• Add a public static method called “getMaxCoins” that accepts an integer array called “coins, ” together with the parameters “integer start” and “integer end, ” and returns an integer result.
• Return zero if start exceeds finish.
• Return dp[start][end] if dp[start][end] is not equal to -1.
• Create the variables option1 and option2 as two integers.
• GetMaxCoins with parameters coins, start+1, end-1, and getMaxCoins with parameters coins, start, end-2 are called recursively with the option1 set to coins[end] plus the minimum value in between.
• Option 2 should be set to coins[start] plus the minimum value in between calls to the recursive functions getMaxCoins with the arguments coins, start+2, end, and getMaxCoins with the arguments coins, start+1, end-1.
• Set the highest value possible between options 1 and 2 for dp[start][end].
• Bring back dp[start][end].
• Make a public static method called maxCoins that receives an integer value as a return parameter and accepts integer array coins and an integer n as input arguments.
• To add -1 values to the dp array, use a nested loop.
• Return the value of the getMaxCoins method with parameters coins, 0, n-1

Below is the code implementation of the above approach:

## C++14

 `// C++ code of the above approach``#include ``using` `namespace` `std;` `int` `dp[1002][1002];` `// Returns the maximum coins that``// can be collected from start to end``int` `getMaxCoins(``int` `coins[], ``int` `start, ``int` `end)``{``    ``// Base case: When start index is``    ``// greater than end index``    ``if` `(start > end) {``        ``return` `0;``    ``}` `    ``// If we have already computed the``    ``// solution for this sub-problem``    ``if` `(dp[start][end] != -1) {``        ``return` `dp[start][end];``    ``}` `    ``// Case 1: Choose the last coin,``    ``// then we can choose between the``    ``// first and second-last coins``    ``int` `option1``        ``= coins[end]``          ``+ min(getMaxCoins(coins, start + 1, end - 1),``                ``getMaxCoins(coins, start, end - 2));` `    ``// Case 2: Choose the first coin,``    ``// then we can choose between the``    ``// second and last coins``    ``int` `option2``        ``= coins[start]``          ``+ min(getMaxCoins(coins, start + 2, end),``                ``getMaxCoins(coins, start + 1, end - 1));` `    ``// Store the maximum coins that``    ``// can be collected from start``    ``// to end``    ``dp[start][end] = max(option1, option2);` `    ``return` `dp[start][end];``}` `int` `maxCoins(``int` `coins[], ``int` `n)``{``    ``// Initialize the DP array with -1``    ``memset``(dp, -1, ``sizeof``(dp));` `    ``return` `getMaxCoins(coins, 0, n - 1);``}` `// Driver code``int` `main()``{``    ``int` `coins[] = { 8, 15, 3, 7 };``    ``int` `n = ``sizeof``(coins) / ``sizeof``(coins[0]);``    ``int` `maxCoin = maxCoins(coins, n);` `    ``// Function call``    ``cout << maxCoin << endl;` `    ``return` `0;``}`

## Java

 `// Java code of the above approach``import` `java.util.*;` `class` `GfG {``    ``public` `static` `int` `dp[][] = ``new` `int``[``1002``][``1002``];` `    ``// Returns the maximum coins that``    ``// can be collected from start to end``    ``public` `static` `int` `getMaxCoins(``int``[] coins, ``int` `start,``                                  ``int` `end)``    ``{` `        ``// Base case: When start index is``        ``// greater than end index``        ``if` `(start > end) {``            ``return` `0``;``        ``}` `        ``// If we have already computed the``        ``// solution for this sub-problem``        ``if` `(dp[start][end] != -``1``) {``            ``return` `dp[start][end];``        ``}` `        ``// Case 1: Choose the last coin,``        ``// then we can choose between the``        ``// first and second-last coins``        ``int` `option1``            ``= coins[end]``              ``+ Math.min(``                    ``getMaxCoins(coins, start + ``1``, end - ``1``),``                    ``getMaxCoins(coins, start, end - ``2``));` `        ``// Case 2: Choose the first coin,``        ``// then we can choose between the``        ``// second and last coins``        ``int` `option2``            ``= coins[start]``              ``+ Math.min(``                    ``getMaxCoins(coins, start + ``2``, end),``                    ``getMaxCoins(coins, start + ``1``, end - ``1``));` `        ``// Store the maximum coins that``        ``// can be collected from start``        ``// to end``        ``dp[start][end] = Math.max(option1, option2);` `        ``return` `dp[start][end];``    ``}` `    ``public` `static` `int` `maxCoins(``int``[] coins, ``int` `n)``    ``{` `        ``// Initialize the DP array with -1``        ``for` `(``int` `i = ``0``; i < ``1001``; i++) {``            ``Arrays.fill(dp[i], -``1``);``        ``}` `        ``return` `getMaxCoins(coins, ``0``, n - ``1``);``    ``}` `    ``// Driver code``    ``public` `static` `void` `main(String args[])``    ``{``        ``int``[] coins = { ``8``, ``15``, ``3``, ``7` `};``        ``int` `n = coins.length;``        ``int` `maxCoins = maxCoins(coins, n);` `        ``// Function call``        ``System.out.println(maxCoins);``    ``}``}`

## Python3

 `class` `GfG:``    ``dp ``=` `[[``-``1` `for` `i ``in` `range``(``1002``)] ``for` `j ``in` `range``(``1002``)]` `    ``# Returns the maximum coins that``    ``# can be collected from start to end``    ``def` `getMaxCoins(``self``, coins, start, end):``        ``# Base case: When start index is``        ``# greater than end index``        ``if` `start > end:``            ``return` `0` `        ``# If we have already computed the``        ``# solution for this sub-problem``        ``if` `self``.dp[start][end] !``=` `-``1``:``            ``return` `self``.dp[start][end]` `        ``# Case 1: Choose the last coin,``        ``# then we can choose between the``        ``# first and second-last coins``        ``option1 ``=` `coins[end] ``+` `min``(``self``.getMaxCoins(coins, start ``+` `1``, end ``-` `1``), ``self``.getMaxCoins(coins, start, end ``-` `2``))` `        ``# Case 2: Choose the first coin,``        ``# then we can choose between the``        ``# second and last coins``        ``option2 ``=` `coins[start] ``+` `min``(``self``.getMaxCoins(coins, start ``+` `2``, end), ``self``.getMaxCoins(coins, start ``+` `1``, end ``-` `1``))` `        ``# Store the maximum coins that``        ``# can be collected from start``        ``# to end``        ``self``.dp[start][end] ``=` `max``(option1, option2)` `        ``return` `self``.dp[start][end]` `    ``def` `maxCoins(``self``, coins, n):``        ``# Initialize the DP array with -1``        ``for` `i ``in` `range``(``1001``):``            ``for` `j ``in` `range``(``1001``):``                ``self``.dp[i][j] ``=` `-``1` `        ``return` `self``.getMaxCoins(coins, ``0``, n ``-` `1``)` `# Driver code``if` `__name__ ``=``=` `'__main__'``:``    ``coins ``=` `[``8``, ``15``, ``3``, ``7``]``    ``n ``=` `len``(coins)``    ``gfg ``=` `GfG()``    ``maxCoins ``=` `gfg.maxCoins(coins, n)` `    ``# Function call``    ``print``(maxCoins)`

## C#

 `using` `System;` `class` `GFG {``    ``public` `static` `int``[,] dp = ``new` `int``[1002, 1002];` `    ``// Returns the maximum coins that can be collected from start to end``    ``public` `static` `int` `getMaxCoins(``int``[] coins, ``int` `start, ``int` `end) {``        ``// Base case: When start index is greater than end index``        ``if` `(start > end) {``            ``return` `0;``        ``}` `        ``// If we have already computed the solution for this sub-problem``        ``if` `(dp[start, end] != -1) {``            ``return` `dp[start, end];``        ``}` `        ``// Case 1: Choose the last coin, then we can choose ``       ``// between the first and second-last coins``        ``int` `option1 = ``          ``coins[end] + Math.Min(getMaxCoins(coins, start + 1, end - 1), ``                                ``getMaxCoins(coins, start, end - 2));` `        ``// Case 2: Choose the first coin, ``       ``// then we can choose between the second and last coins``        ``int` `option2 = ``          ``coins[start] + Math.Min(getMaxCoins(coins, start + 2, end), ``                                  ``getMaxCoins(coins, start + 1, end - 1));` `        ``// Store the maximum coins that can be collected from start to end``        ``dp[start, end] = Math.Max(option1, option2);` `        ``return` `dp[start, end];``    ``}` `    ``public` `static` `int` `maxCoins(``int``[] coins, ``int` `n) {``        ``// Initialize the DP array with -1``        ``for` `(``int` `i = 0; i < 1001; i++) {``            ``for` `(``int` `j = 0; j < 1001; j++) {``                ``dp[i,j] = -1;``            ``}``        ``}` `        ``return` `getMaxCoins(coins, 0, n - 1);``    ``}` `    ``// Driver code``    ``public` `static` `void` `Main() {``        ``int``[] coins = {8, 15, 3, 7};``        ``int` `n = coins.Length;``        ``int` `mxCoins = maxCoins(coins, n);` `        ``// Function call``        ``Console.WriteLine(mxCoins);``    ``}``}`

## Javascript

 `// JavaScript code of the above approach` `// Returns the maximum coins that``// can be collected from start to end``function` `getMaxCoins(coins, start, end, dp) {``    ` `    ``// Base case: When start index is``    ``// greater than end index``    ``if` `(start > end) {``        ``return` `0;``    ``}` `    ``// If we have already computed the``    ``// solution for this sub-problem``    ``if` `(dp[start][end] != -1) {``        ``return` `dp[start][end];``    ``}` `    ``// Case 1: Choose the last coin,``    ``// then we can choose between the``    ``// first and second-last coins``    ``let option1 =``        ``coins[end]``        ``+ Math.min(getMaxCoins(coins, start + 1, end - 1, dp),``                    ``getMaxCoins(coins, start, end - 2, dp));` `    ``// Case 2: Choose the first coin,``    ``// then we can choose between the``    ``// second and last coins``    ``let option2 =``        ``coins[start]``        ``+ Math.min(getMaxCoins(coins, start + 2, end, dp),``                    ``getMaxCoins(coins, start + 1, end - 1, dp));` `    ``// Store the maximum coins that``    ``// can be collected from start``    ``// to end``    ``dp[start][end] = Math.max(option1, option2);` `    ``return` `dp[start][end];``}` `function` `maxCoins(coins, n) {``    ``let dp = [];` `    ``// Initialize the DP array with -1``    ``for` `(let i = 0; i <= n; i++) {``        ``dp[i] = Array(n).fill(-1);``    ``}` `    ``return` `getMaxCoins(coins, 0, n - 1, dp);``}` `// Driver code``let coins = [ 8, 15, 3, 7 ];``let n = coins.length;``let maxCoin = maxCoins(coins, n);` `// Function call``console.log(maxCoin);``// This code is contributed by prasad264`

Output
```22

```

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

Efficient approach : Using DP Tabulation method ( Iterative approach )

The approach to solve this problem is same but DP tabulation(bottom-up) method is better then Dp + memoization(top-down) because memoization method needs extra stack space of recursion calls.

Steps to solve this problem :

• Create a DP of size n*n to store the solution of the subproblems .
• Now Iterate over subproblems to get the value of current problem form previous computation of subproblems stored in DP
• Return the final solution stored in dp[0][n – 1].

Implementation :

## C++

 `// C++ code of the above approach``#include ``using` `namespace` `std;` `// Returns the maximum coins that``// can be collected from start to end``int` `maxCoins(``int` `coins[], ``int` `n) {``    ``// Base case``    ``if` `(n == 0)``        ``return` `0;``        ` `    ``//intialize dp ``    ``int` `dp[n][n];``    ` `    ``//iterate over subproblems``    ``for` `(``int` `len = 1; len <= n; len++) {``        ``for` `(``int` `start = 0; start <= n - len; start++) {``            ``int` `end = start + len - 1;``            ``int` `x = ((start + 2 <= end) ? dp[start + 2][end] : 0);``            ``int` `y = ((start + 1 <= end - 1) ? dp[start + 1][end - 1] : 0);``            ``int` `z = ((start <= end - 2) ? dp[start][end - 2] : 0);``            ` `            ``//current value``            ``dp[start][end] = max(coins[start] + min(x, y), coins[end] + min(y, z));``        ``}``    ``}``    ` `    ``//return answer``    ``return` `dp[0][n - 1];``}` `//Driver Code``int` `main() {    ``    ``int` `coins[] = { 8, 15, 3, 7 };``    ``int` `n = ``sizeof``(coins) / ``sizeof``(coins[0]);``    ``int` `maxCoin = maxCoins(coins, n);` `    ``cout << maxCoin << endl;` `    ``return` `0;``}`

## Java

 `public` `class` `MaxCoinsCollection {` `    ``// Returns the maximum coins that can be collected from start to end``    ``public` `static` `int` `maxCoins(``int``[] coins) {``        ``int` `n = coins.length;``        ` `        ``// Initialize a 2D array to store the maximum coins``        ``int``[][] dp = ``new` `int``[n][n];` `        ``// Iterate over subproblems``        ``for` `(``int` `len = ``1``; len <= n; len++) {``            ``for` `(``int` `start = ``0``; start <= n - len; start++) {``                ``int` `end = start + len - ``1``;``                ``int` `x = (start + ``2` `<= end) ? dp[start + ``2``][end] : ``0``;``                ``int` `y = (start + ``1` `<= end - ``1``) ? dp[start + ``1``][end - ``1``] : ``0``;``                ``int` `z = (start <= end - ``2``) ? dp[start][end - ``2``] : ``0``;` `                ``// Calculate the current value``                ``dp[start][end] = Math.max(coins[start] + Math.min(x, y), coins[end] + Math.min(y, z));``            ``}``        ``}` `        ``// Return the answer``        ``return` `dp[``0``][n - ``1``];``    ``}` `    ``// Driver Code``    ``public` `static` `void` `main(String[] args) {``        ``int``[] coins = { ``8``, ``15``, ``3``, ``7` `};``        ``int` `maxCoin = maxCoins(coins);` `        ``System.out.println(maxCoin);``    ``}``}`

## Python3

 `# Python code of the above approach``def` `maxCoins(coins, n):``    ``# Base case``    ``if` `n ``=``=` `0``:``        ``return` `0``    ` `    ``# intialize dp``    ``dp ``=` `[[``0` `for` `j ``in` `range``(n)] ``for` `i ``in` `range``(n)]``    ` `    ``# iterate over subproblems``    ``for` `length ``in` `range``(``1``, n``+``1``):``        ``for` `start ``in` `range``(n ``-` `length ``+` `1``):``            ``end ``=` `start ``+` `length ``-` `1``            ``x ``=` `dp[start ``+` `2``][end] ``if` `start ``+` `2` `<``=` `end ``else` `0``            ``y ``=` `dp[start ``+` `1``][end ``-` `1``] ``if` `start ``+` `1` `<``=` `end ``-` `1` `else` `0``            ``z ``=` `dp[start][end ``-` `2``] ``if` `start <``=` `end ``-` `2` `else` `0``            ` `            ``# current value``            ``dp[start][end] ``=` `max``(coins[start] ``+` `min``(x, y), coins[end] ``+` `min``(y, z))``    ` `    ``# return answer``    ``return` `dp[``0``][n ``-` `1``]` `# Driver Code``coins ``=` `[``8``, ``15``, ``3``, ``7``]``n ``=` `len``(coins)``maxCoin ``=` `maxCoins(coins, n)` `print``(maxCoin)` `# This code is contributed by Sakshi`

## C#

 `using` `System;` `class` `Program``{``    ``// Returns the maximum coins that can be collected from start to end``    ``static` `int` `MaxCoins(``int``[] coins, ``int` `n)``    ``{``        ``// Base case``        ``if` `(n == 0)``            ``return` `0;` `        ``// Initialize dp``        ``int``[,] dp = ``new` `int``[n, n];` `        ``// Iterate over subproblems``        ``for` `(``int` `len = 1; len <= n; len++)``        ``{``            ``for` `(``int` `start = 0; start <= n - len; start++)``            ``{``                ``int` `end = start + len - 1;``                ``int` `x = (start + 2 <= end) ? dp[start + 2, end] : 0;``                ``int` `y = (start + 1 <= end - 1) ? dp[start + 1, end - 1] : 0;``                ``int` `z = (start <= end - 2) ? dp[start, end - 2] : 0;` `                ``// Current value``                ``dp[start, end] = Math.Max(coins[start] + Math.Min(x, y), coins[end] + Math.Min(y, z));``            ``}``        ``}` `        ``// Return answer``        ``return` `dp[0, n - 1];``    ``}` `    ``// Driver Code``    ``static` `void` `Main(``string``[] args)``    ``{``        ``int``[] coins = { 8, 15, 3, 7 };``        ``int` `n = coins.Length;``        ``int` `maxCoin = MaxCoins(coins, n);` `        ``Console.WriteLine(maxCoin);``    ``}``}`

## Javascript

 `function` `maxCoins(coins) {``    ``const n = coins.length;` `    ``// Base case``    ``if` `(n === 0) {``        ``return` `0;``    ``}` `    ``// Initialize a 2D array for dynamic programming``    ``const dp = ``new` `Array(n).fill(0).map(() => ``new` `Array(n).fill(0));` `    ``// Iterate over subproblems``    ``for` `(let len = 1; len <= n; len++) {``        ``for` `(let start = 0; start <= n - len; start++) {``            ``const end = start + len - 1;``            ``const x = start + 2 <= end ? dp[start + 2][end] : 0;``            ``const y = start + 1 <= end - 1 ? dp[start + 1][end - 1] : 0;``            ``const z = start <= end - 2 ? dp[start][end - 2] : 0;` `            ``// Current value``            ``dp[start][end] = Math.max(coins[start] + Math.min(x, y), coins[end] + Math.min(y, z));``        ``}``    ``}` `    ``// Return the answer``    ``return` `dp[0][n - 1];``}` `// Driver Code``const coins = [8, 15, 3, 7];``const maxCoin = maxCoins(coins);``console.log(maxCoin);`

Output

`22`

Time Complexity: O(N^2)

Auxiliary Space: O(N^2)

Previous
Next