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.
To win the maximum amount, you need to consider both your turn and your opponent’s turn simultaneously, anticipating their move. Hence, this is a dynamic programming problem, not a simple greedy one.
Instead of choosing the coin greedily, you must evaluate both options (first coin or last coin) and simulate the opponent’s optimal choice to assess the best possible move at every step.
Use the following recurrence relation to compute the optimal score:
dp[i][j] represents the maximum amount you can collect when considering coins from index i to j:
If you pick the first coin: dp[i][j] = nums[i] + min(dp[i+2][j], dp[i+1][j-1])
If you pick the last coin: dp[i][j] = nums[j] + min(dp[i+1][j-1], dp[i][j-2])
The min part represents that your opponent plays optimally to reduce your score.
The base cases are:
When there is only one coin left: dp[i][i] = nums[i].
classSolution:
defmaxCoins(self, nums):
n = len(nums)
# Initialize dp array dp = [[0] * n for _ in range(n)]
# Fill the dp arrayfor length in range(1, n+1): # Subarrays of length 1 to nfor i in range(n - length +1):
j = i + length -1# Base casesif i == j:
dp[i][j] = nums[i]
else:
# Calculate dp[i][j] using the recurrence relation left_pick = nums[i] + min(dp[i+2][j] if i+2<= j else0,
dp[i+1][j-1] if i+1<= j-1else0)
right_pick = nums[j] + min(dp[i+1][j-1] if i+1<= j-1else0,
dp[i][j-2] if i <= j-2else0)
dp[i][j] = max(left_pick, right_pick)
return dp[0][n-1]
# Example usagenums = [8, 15, 3, 7]
print(Solution().maxCoins(nums)) # Output: 22