Problem
In front of you is a row of N coins, with values v_1, v_2, ..., v_n
.
You are asked to play the following game. You and an opponent take turns choosing either the first or last coin from the row, removing it from the row, and receiving the value of the coin.
Write a program that returns the maximum amount of money you can win with certainty, if you move first, assuming your opponent plays optimally.
OR
In this game, Alice and Bob take turns removing coins from either end of a line of n
coins, where each coin has a specific value. Both players aim to collect coins such that the total value of their set is maximized. Alice starts first, and both players play optimally, always considering the best possible choices to secure the highest total value while leaving the worst options for their opponent.
Your task is to compute the maximum sum of values Alice can guarantee herself, assuming both Alice and Bob pick coins using optimal strategies.
Examples
Example 1
|
|
Example 2
|
|
Solution
Method 1 - Using DP
Reasoning
-
Dynamic Programming Approach: The problem is not as simple as greedy decision-making where you always pick the coin with the largest value at the ends. Since your opponent also plays optimally to minimise your final score, you need to anticipate their moves in every situation. This makes it a perfect candidate for dynamic programming, where decisions are made based on smaller sub-problems.
-
Anticipating Moves: At every step, you must evaluate both possible options (taking the first or last coin from the line) and factor in the best move your opponent will make next. By simulating the opponent’s optimal decisions, you can determine the maximum score you are guaranteed to collect from the entire line of coins.
-
Core Formula (Recurrence Relation):
-
Let
dp[i][j]
represent the maximum value you can secure when working with the subarray of coins between indexi
andj
inclusively:- Option 1: Choose the first coin at index
i
:- You gain the value of the first coin (
nums[i]
), but your opponent will then select the move that minimises your future options. - Result:
nums[i] + min(dp[i+2][j], dp[i+1][j-1])
- You gain the value of the first coin (
- Option 2: Choose the last coin at index
j
:- You gain the value of the last coin (
nums[j]
), while your opponent similarly minimises your options. - Result:
nums[j] + min(dp[i+1][j-1], dp[i][j-2])
- You gain the value of the last coin (
- Option 1: Choose the first coin at index
-
Here is how we can visualize it.
-
Combine both options and take the maximum value:
1 2
dp[i][j] = max(nums[i] + min(dp[i+2][j], dp[i+1][j-1]), nums[j] + min(dp[i+1][j-1], dp[i][j-2]))
-
-
Base cases:
- When there is only one coin left (
i == j
), the result is simplydp[i][i] = nums[i]
. - For two coins remaining (
i + 1 == j
), the result isdp[i][j] = max(nums[i], nums[j])
.
- When there is only one coin left (
Approach
- Use a 2D
dp
array wheredp[i][j]
stores the maximum value you can secure from coins between indicesi
andj
. - Build the table
dp
iteratively, starting with the smallest sub-problems:- For diagonal elements (one coin),
dp[i][i] = nums[i]
. - For two coins, choose the maximum:
dp[i][j] = max(nums[i], nums[j])
.
- For diagonal elements (one coin),
- For larger subarrays, evaluate using the above recurrence relation.
- Finally, return
dp[0][n-1]
, representing the best value you can collect for the whole array.
Since the optimal choice at every step depends on the minimised future value (your opponent’s strategy), this approach guarantees that you win the maximum possible amount irrespective of your opponent’s moves.
Code
|
|
|
|
Complexity
- ⏰ Time complexity:
O(n^2)
: We fill ann x n
table. - 🧺 Space complexity:
O(n^2)
: The 2Ddp
array stores results for all subarrays.