返回介绍

solution / 1800-1899 / 1872.Stone Game VIII / README_EN

发布于 2024-06-17 01:03:13 字数 9928 浏览 0 评论 0 收藏 0

1872. Stone Game VIII

中文文档

Description

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, while the number of stones is more than one, they will do the following:

  1. Choose an integer x > 1, and remove the leftmost x stones from the row.
  2. Add the sum of the removed stones' values to the player's score.
  3. Place a new stone, whose value is equal to that sum, on the left side of the row.

The game stops when only one stone is left in the row.

The score difference between Alice and Bob is (Alice's score - Bob's score). Alice's goal is to maximize the score difference, and Bob's goal is the minimize the score difference.

Given an integer array stones of length n where stones[i] represents the value of the ith stone from the left, return _the score difference between Alice and Bob if they both play optimally._

 

Example 1:


Input: stones = [-1,2,-3,4,-5]

Output: 5

Explanation:

- Alice removes the first 4 stones, adds (-1) + 2 + (-3) + 4 = 2 to her score, and places a stone of

  value 2 on the left. stones = [2,-5].

- Bob removes the first 2 stones, adds 2 + (-5) = -3 to his score, and places a stone of value -3 on

  the left. stones = [-3].

The difference between their scores is 2 - (-3) = 5.

Example 2:


Input: stones = [7,-6,5,10,5,-2,-6]

Output: 13

Explanation:

- Alice removes all stones, adds 7 + (-6) + 5 + 10 + 5 + (-2) + (-6) = 13 to her score, and places a

  stone of value 13 on the left. stones = [13].

The difference between their scores is 13 - 0 = 13.

Example 3:


Input: stones = [-10,-12]

Output: -22

Explanation:

- Alice can only make one move, which is to remove both stones. She adds (-10) + (-12) = -22 to her

  score and places a stone of value -22 on the left. stones = [-22].

The difference between their scores is (-22) - 0 = -22.

 

Constraints:

  • n == stones.length
  • 2 <= n <= 105
  • -104 <= stones[i] <= 104

Solutions

Solution 1: Prefix Sum + Memoization Search

According to the problem description, each time we take the leftmost $x$ stones, add their sum to our score, and then put a stone with this sum value on the leftmost side, it is equivalent to merging these $x$ stones into a stone with this sum value, and the prefix sum remains unchanged.

We can use a prefix sum array $s$ of length $n$ to represent the prefix sum of the array $stones$, where $s[i]$ represents the sum of the elements $stones[0..i]$.

Next, we design a function $dfs(i)$, which means that we currently take stones from $stones[i:]$, and return the maximum score difference that the current player can get.

The execution process of the function $dfs(i)$ is as follows:

  • If $i \geq n - 1$, it means that we can only take all the stones at present, so we return $s[n - 1]$.
  • Otherwise, we can choose to take all the stones from $stones[i + 1:]$, and the score difference obtained is $dfs(i + 1)$; we can also choose to take the stones $stones[:i]$, and the score difference obtained is $s[i] - dfs(i + 1)$. We take the maximum of the two situations, which is the maximum score difference that the current player can get.

Finally, we can get the score difference between Alice and Bob as $dfs(1)$, that is, Alice must start the game by taking stones from $stones[1:]$.

To avoid repeated calculations, we can use memoization search.

The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the length of the array $stones$.

class Solution:
  def stoneGameVIII(self, stones: List[int]) -> int:
    @cache
    def dfs(i: int) -> int:
      if i >= len(stones) - 1:
        return s[-1]
      return max(dfs(i + 1), s[i] - dfs(i + 1))

    s = list(accumulate(stones))
    return dfs(1)
class Solution {
  private Integer[] f;
  private int[] s;
  private int n;

  public int stoneGameVIII(int[] stones) {
    n = stones.length;
    f = new Integer[n];
    for (int i = 1; i < n; ++i) {
      stones[i] += stones[i - 1];
    }
    s = stones;
    return dfs(1);
  }

  private int dfs(int i) {
    if (i >= n - 1) {
      return s[i];
    }
    if (f[i] == null) {
      f[i] = Math.max(dfs(i + 1), s[i] - dfs(i + 1));
    }
    return f[i];
  }
}
class Solution {
public:
  int stoneGameVIII(vector<int>& stones) {
    int n = stones.size();
    for (int i = 1; i < n; ++i) {
      stones[i] += stones[i - 1];
    }
    int f[n];
    memset(f, -1, sizeof(f));
    function<int(int)> dfs = [&](int i) -> int {
      if (i >= n - 1) {
        return stones[i];
      }
      if (f[i] == -1) {
        f[i] = max(dfs(i + 1), stones[i] - dfs(i + 1));
      }
      return f[i];
    };
    return dfs(1);
  }
};
func stoneGameVIII(stones []int) int {
  n := len(stones)
  f := make([]int, n)
  for i := range f {
    f[i] = -1
  }
  for i := 1; i < n; i++ {
    stones[i] += stones[i-1]
  }
  var dfs func(int) int
  dfs = func(i int) int {
    if i >= n-1 {
      return stones[i]
    }
    if f[i] == -1 {
      f[i] = max(dfs(i+1), stones[i]-dfs(i+1))
    }
    return f[i]
  }
  return dfs(1)
}
function stoneGameVIII(stones: number[]): number {
  const n = stones.length;
  const f: number[] = Array(n).fill(-1);
  for (let i = 1; i < n; ++i) {
    stones[i] += stones[i - 1];
  }
  const dfs = (i: number): number => {
    if (i >= n - 1) {
      return stones[i];
    }
    if (f[i] === -1) {
      f[i] = Math.max(dfs(i + 1), stones[i] - dfs(i + 1));
    }
    return f[i];
  };
  return dfs(1);
}

Solution 2: Prefix Sum + Dynamic Programming

We can also use dynamic programming to solve this problem.

Similar to Solution 1, we first use a prefix sum array $s$ of length $n$ to represent the prefix sum of the array $stones$, where $s[i]$ represents the sum of the elements $stones[0..i]$.

We define $f[i]$ to represent the maximum score difference that the current player can get when taking stones from $stones[i:]$.

If the player chooses to take the stones $stones[:i]$, then the score obtained is $s[i]$. At this time, the other player will take stones from $stones[i+1:]$, and the maximum score difference that the other player can get is $f[i+1]$. Therefore, the maximum score difference that the current player can get is $s[i] - f[i+1]$.

If the player chooses to take stones from $stones[i+1:]$, then the maximum score difference obtained is $f[i+1]$.

Therefore, we can get the state transition equation:

$$ f[i] = \max{s[i] - f[i+1], f[i+1]} $$

Finally, we can get the score difference between Alice and Bob as $f[1]$, that is, Alice must start the game by taking stones from $stones[1:]$.

We notice that $f[i]$ is only related to $f[i+1]$, so we only need to use a variable $f$ to represent $f[i]$.

The time complexity is $O(n)$, and the space complexity is $O(1)$. Here, $n$ is the length of the array $stones$.

class Solution:
  def stoneGameVIII(self, stones: List[int]) -> int:
    s = list(accumulate(stones))
    f = s[-1]
    for i in range(len(s) - 2, 0, -1):
      f = max(f, s[i] - f)
    return f
class Solution {
  public int stoneGameVIII(int[] stones) {
    int n = stones.length;
    for (int i = 1; i < n; ++i) {
      stones[i] += stones[i - 1];
    }
    int f = stones[n - 1];
    for (int i = n - 2; i > 0; --i) {
      f = Math.max(f, stones[i] - f);
    }
    return f;
  }
}
class Solution {
public:
  int stoneGameVIII(vector<int>& stones) {
    int n = stones.size();
    for (int i = 1; i < n; ++i) {
      stones[i] += stones[i - 1];
    }
    int f = stones.back();
    for (int i = n - 2; i; --i) {
      f = max(f, stones[i] - f);
    }
    return f;
  }
};
function stoneGameVIII(stones: number[]): number {
  const n = stones.length;
  for (let i = 1; i < n; ++i) {
    stones[i] += stones[i - 1];
  }
  let f = stones[n - 1];
  for (let i = n - 2; i; --i) {
    f = Math.max(f, stones[i] - f);
  }
  return f;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文