comments | difficulty | edit_url | rating | source | tags | ||||
---|---|---|---|---|---|---|---|---|---|
true |
Medium |
1951 |
Weekly Contest 219 Q3 |
|
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
First, we preprocess to get the prefix sum array
Next, we design a function
The calculation process of the function
- If
, it means there are no stones currently, so return ; - Otherwise, the first player has two choices, which are to remove
or , and then calculate the score difference, i.e., and . We take the larger of the two as the return value of .
During the process, we use memorization search, i.e., use an array
The time complexity is
class Solution:
def stoneGameVII(self, stones: List[int]) -> int:
@cache
def dfs(i: int, j: int) -> int:
if i > j:
return 0
a = s[j + 1] - s[i + 1] - dfs(i + 1, j)
b = s[j] - s[i] - dfs(i, j - 1)
return max(a, b)
s = list(accumulate(stones, initial=0))
ans = dfs(0, len(stones) - 1)
dfs.cache_clear()
return ans
class Solution {
private int[] s;
private Integer[][] f;
public int stoneGameVII(int[] stones) {
int n = stones.length;
s = new int[n + 1];
f = new Integer[n][n];
for (int i = 0; i < n; ++i) {
s[i + 1] = s[i] + stones[i];
}
return dfs(0, n - 1);
}
private int dfs(int i, int j) {
if (i > j) {
return 0;
}
if (f[i][j] != null) {
return f[i][j];
}
int a = s[j + 1] - s[i + 1] - dfs(i + 1, j);
int b = s[j] - s[i] - dfs(i, j - 1);
return f[i][j] = Math.max(a, b);
}
}
class Solution {
public:
int stoneGameVII(vector<int>& stones) {
int n = stones.size();
int f[n][n];
memset(f, 0, sizeof f);
int s[n + 1];
s[0] = 0;
for (int i = 0; i < n; ++i) {
s[i + 1] = s[i] + stones[i];
}
function<int(int, int)> dfs = [&](int i, int j) {
if (i > j) {
return 0;
}
if (f[i][j]) {
return f[i][j];
}
int a = s[j + 1] - s[i + 1] - dfs(i + 1, j);
int b = s[j] - s[i] - dfs(i, j - 1);
return f[i][j] = max(a, b);
};
return dfs(0, n - 1);
}
};
func stoneGameVII(stones []int) int {
n := len(stones)
s := make([]int, n+1)
f := make([][]int, n)
for i, x := range stones {
s[i+1] = s[i] + x
f[i] = make([]int, n)
}
var dfs func(int, int) int
dfs = func(i, j int) int {
if i > j {
return 0
}
if f[i][j] != 0 {
return f[i][j]
}
a := s[j+1] - s[i+1] - dfs(i+1, j)
b := s[j] - s[i] - dfs(i, j-1)
f[i][j] = max(a, b)
return f[i][j]
}
return dfs(0, n-1)
}
function stoneGameVII(stones: number[]): number {
const n = stones.length;
const s: number[] = Array(n + 1).fill(0);
for (let i = 0; i < n; ++i) {
s[i + 1] = s[i] + stones[i];
}
const f: number[][] = Array.from({ length: n }, () => Array(n).fill(0));
const dfs = (i: number, j: number): number => {
if (i > j) {
return 0;
}
if (f[i][j]) {
return f[i][j];
}
const a = s[j + 1] - s[i + 1] - dfs(i + 1, j);
const b = s[j] - s[i] - dfs(i, j - 1);
return (f[i][j] = Math.max(a, b));
};
return dfs(0, n - 1);
}
We can convert the memoization search in Solution 1 into dynamic programming. We define
The state transition equation is as follows:
When calculating
Finally, the answer is
The time complexity is
class Solution:
def stoneGameVII(self, stones: List[int]) -> int:
s = list(accumulate(stones, initial=0))
n = len(stones)
f = [[0] * n for _ in range(n)]
for i in range(n - 2, -1, -1):
for j in range(i + 1, n):
a = s[j + 1] - s[i + 1] - f[i + 1][j]
b = s[j] - s[i] - f[i][j - 1]
f[i][j] = max(a, b)
return f[0][-1]
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[][] f = new int[n][n];
for (int i = n - 2; i >= 0; --i) {
for (int j = i + 1; j < n; ++j) {
int a = s[j + 1] - s[i + 1] - f[i + 1][j];
int b = s[j] - s[i] - f[i][j - 1];
f[i][j] = Math.max(a, b);
}
}
return f[0][n - 1];
}
}
class Solution {
public:
int stoneGameVII(vector<int>& stones) {
int n = stones.size();
int s[n + 1];
memset(s, 0, sizeof(s));
for (int i = 0; i < n; ++i) {
s[i + 1] = s[i] + stones[i];
}
int f[n][n];
memset(f, 0, sizeof(f));
for (int i = n - 2; i >= 0; --i) {
for (int j = i + 1; j < n; ++j) {
int a = s[j + 1] - s[i + 1] - f[i + 1][j];
int b = s[j] - s[i] - f[i][j - 1];
f[i][j] = max(a, b);
}
}
return f[0][n - 1];
}
};
func stoneGameVII(stones []int) int {
n := len(stones)
s := make([]int, n+1)
for i, x := range stones {
s[i+1] = s[i] + x
}
f := make([][]int, n)
for i := range f {
f[i] = make([]int, n)
}
for i := n - 2; i >= 0; i-- {
for j := i + 1; j < n; j++ {
f[i][j] = max(s[j+1]-s[i+1]-f[i+1][j], s[j]-s[i]-f[i][j-1])
}
}
return f[0][n-1]
}
function stoneGameVII(stones: number[]): number {
const n = stones.length;
const s: number[] = Array(n + 1).fill(0);
for (let i = 0; i < n; ++i) {
s[i + 1] = s[i] + stones[i];
}
const f: number[][] = Array.from({ length: n }, () => Array(n).fill(0));
for (let i = n - 2; ~i; --i) {
for (let j = i + 1; j < n; ++j) {
f[i][j] = Math.max(s[j + 1] - s[i + 1] - f[i + 1][j], s[j] - s[i] - f[i][j - 1]);
}
}
return f[0][n - 1];
}