Alice and Bob take turns playing a game, with Alice starting first.
There are n stones arranged in a row. On each player's turn, they can remove either the leftmost stone or the rightmost stone from the row and receive points equal to the sum of the remaining stones' values in the row. The winner is the one with the higher score when there are no stones left to remove.
Bob found that he will always lose this game (poor Bob, he always loses), so he decided to minimize the score's difference. Alice's goal is to maximize the difference in the score.
Given an array of integers stones where stones[i] represents the value of the ith stone from the left, return the difference in Alice and Bob's score if they both play optimally.
Example 1:
Input: stones = [5,3,1,4,2]
Output: 6
Explanation:
- Alice removes 2 and gets 5 + 3 + 1 + 4 = 13 points. Alice = 13, Bob = 0, stones = [5,3,1,4].
- Bob removes 5 and gets 3 + 1 + 4 = 8 points. Alice = 13, Bob = 8, stones = [3,1,4].
- Alice removes 3 and gets 1 + 4 = 5 points. Alice = 18, Bob = 8, stones = [1,4].
- Bob removes 1 and gets 4 points. Alice = 18, Bob = 12, stones = [4].
- Alice removes 4 and gets 0 points. Alice = 18, Bob = 12, stones = [].
The score difference is 18 - 12 = 6.
Each turn removes one end and scores the sum of what remains. The first-player minus second-player gap on an interval is a memoized game: \(dfs(i,j)\) is the current player's advantage.
Prefix sums \(s\) give the score after dropping the left or right end; take the larger of \(s[j+1]-s[i+1]-dfs(i+1,j)\) and \(s[j]-s[i]-dfs(i,j-1)\).
First, we preprocess to get the prefix sum array \(s\), where \(s[i]\) represents the total sum of the first \(i\) stones.
Next, we design a function \(dfs(i, j)\), which represents the score difference between the first and second players when the remaining stones are \(stones[i], stones[i + 1], \dots, stones[j]\). The answer is \(dfs(0, n - 1)\).
The calculation process of the function \(dfs(i, j)\) is as follows:
If \(i > j\), it means there are no stones currently, so return \(0\);
Otherwise, the first player has two choices, which are to remove \(stones[i]\) or \(stones[j]\), and then calculate the score difference, i.e., \(a = s[j + 1] - s[i + 1] - dfs(i + 1, j)\) and \(b = s[j] - s[i] - dfs(i, j - 1)\). We take the larger of the two as the return value of \(dfs(i, j)\).
During the process, we use memorization search, i.e., use an array \(f\) to record the return value of the function \(dfs(i, j)\), to avoid repeated calculations.
The time complexity is \(O(n^2)\), and the space complexity is \(O(n^2)\). Here, \(n\) is the number of stones.
Solution 1 already fills this interval with decreasing \(i\) and increasing \(j\). The \(f[i][j]\) below is that same table.
Solution 1 already fills this transition with decreasing \(i\) and increasing \(j\). Define \(f[i][j]\) as the score difference between the first and second players when the remaining stones are \(stones[i], stones[i + 1], \dots, stones[j]\). Therefore, the answer is \(f[0][n - 1]\).
When calculating \(f[i][j]\), we need to ensure that \(f[i + 1][j]\) and \(f[i][j - 1]\) have been calculated. Therefore, we need to enumerate \(i\) in descending order and \(j\) in ascending order.
Finally, the answer is \(f[0][n - 1]\).
The time complexity is \(O(n^2)\), and the space complexity is \(O(n^2)\). Here, \(n\) is the number of stones.
Enumerating both players' choices is exponential. There can be \(1000\) stones, and the branch that removes the left stone first always advances the left endpoint, so the search has depth \(n\). The current player's advantage on \([i,j]\) depends only on shorter intervals. Let \(f[i][j]\) store that difference, with a single stone worth \(0\), and fill decreasing \(i\) and increasing \(j\): removing the left end scores \(s[j+1]-s[i+1]-f[i+1][j]\), removing the right end scores \(s[j]-s[i]-f[i][j-1]\), and the state keeps the larger one.
Precompute the prefix sums \(s\), where \(s[i]\) is the sum of the first \(i\) stones. Let \(f[i][j]\) be the score difference between the current player and the opponent on \(stones[i], stones[i + 1], \dots, stones[j]\). A single stone has difference \(0\). For \(i\) from \(n-2\) down to \(0\), and for each \(i\) with \(j\) from \(i+1\) to \(n-1\), the shorter states \(f[i+1][j]\) and \(f[i][j-1]\) are already known. Removing the left stone scores \(s[j+1]-s[i+1]-f[i+1][j]\), and removing the right stone scores \(s[j]-s[i]-f[i][j-1]\). \(f[i][j]\) is the larger of the two. The answer is \(f[0][n-1]\).
The time complexity is \(O(n^2)\), and the space complexity is \(O(n^2)\). Here, \(n\) is the number of stones.