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.
Example 2:
Input: stones = [7,90,5,1,100,10,10,2] Output: 122
Constraints:
n == stones.length
2 <= n <= 1000
1 <= stones[i] <= 1000
Alice and Bob play a game with n
stones arranged in a row. Each player takes turns removing either the leftmost or rightmost stone. The player receives points equal to the sum of the remaining stones' values. The player with the higher score wins. The goal is to find the difference in Alice and Bob's scores if they both play optimally. Alice aims to maximize the difference, while Bob aims to minimize it.
This problem can be solved efficiently using dynamic programming. We can build a solution bottom-up, starting with smaller subproblems and building up to the final solution.
Prefix Sum: Calculate the prefix sum of the stones
array. The prefix sum s[i]
represents the sum of stones from index 0 to i-1
. This allows for efficient calculation of the sum of any subarray in O(1) time.
DP Table: Create a 2D DP table dp
of size n x n
, where dp[i][j]
represents the maximum score difference Alice can achieve when playing optimally with the subarray stones[i...j]
.
Base Case: When i > j
(empty subarray), the score difference is 0. Therefore, dp[i][j] = 0
for i > j
.
State Transition: For a given subarray stones[i...j]
, Alice has two choices:
stones[i]
: Alice's score increases by the sum of the remaining stones (s[j+1] - s[i+1]
). Bob then plays optimally on the remaining subarray stones[i+1...j]
, resulting in a score difference of s[j+1] - s[i+1] - dp[i+1][j]
.stones[j]
: Alice's score increases by the sum of the remaining stones (s[j] - s[i]
). Bob then plays optimally on the remaining subarray stones[i...j-1]
, resulting in a score difference of s[j] - s[i] - dp[i][j-1]
.Alice chooses the option that maximizes her score difference. Therefore:
dp[i][j] = max(s[j+1] - s[i+1] - dp[i+1][j], s[j] - s[i] - dp[i][j-1])
Final Result: The final answer is dp[0][n-1]
.
from itertools import accumulate
class Solution:
def stoneGameVII(self, stones: List[int]) -> int:
n = len(stones)
s = list(accumulate(stones, initial=0)) # Prefix sum
dp = [[0] * n for _ in range(n)]
for i in range(n - 2, -1, -1):
for j in range(i + 1, n):
dp[i][j] = max(s[j + 1] - s[i + 1] - dp[i + 1][j], s[j] - s[i] - dp[i][j - 1])
return dp[0][n - 1]
import java.util.Arrays;
class Solution {
public int stoneGameVII(int[] stones) {
int n = stones.length;
int[] s = new int[n + 1];
for (int i = 0; i < n; i++) {
s[i + 1] = s[i] + stones[i];
}
int[][] dp = new int[n][n];
for (int i = n - 2; i >= 0; i--) {
for (int j = i + 1; j < n; j++) {
dp[i][j] = Math.max(s[j + 1] - s[i + 1] - dp[i + 1][j], s[j] - s[i] - dp[i][j - 1]);
}
}
return dp[0][n - 1];
}
}
#include <vector>
#include <numeric>
using namespace std;
class Solution {
public:
int stoneGameVII(vector<int>& stones) {
int n = stones.size();
vector<long long> s(n + 1, 0);
partial_sum(stones.begin(), stones.end(), s.begin() + 1);
vector<vector<long long>> dp(n, vector<long long>(n, 0));
for (int i = n - 2; i >= 0; --i) {
for (int j = i + 1; j < n; ++j) {
dp[i][j] = max(s[j + 1] - s[i + 1] - dp[i + 1][j], s[j] - s[i] - dp[i][j - 1]);
}
}
return (int)dp[0][n - 1];
}
};
These code examples implement the dynamic programming solution. The Python and Java solutions use simple array-based DP tables. The C++ solution uses vector
for the DP table for better flexibility. All have the same O(n^2) time and space complexity. Remember to handle potential integer overflow if input numbers are very large.