Stone Game II

medium dynamic programming game theory suffix sum

Problem

Alice and Bob take turns over a row of stone piles, Alice first. On a turn the player takes all stones from the first X remaining piles, where 1 ≤ X ≤ 2M. Then M becomes max(M, X). M starts at 1. Both play optimally; return the maximum number of stones Alice can collect.

Inputpiles = [2, 7, 9, 4, 4]
Output10
If Alice takes 1 pile she gets 2, then Bob can take up to 2 piles. Playing optimally Alice secures 2 + 4 + 4 = 10.

def stone_game_ii(piles):
    n = len(piles)
    suffix = [0] * (n + 1)
    for i in range(n - 1, -1, -1):
        suffix[i] = suffix[i + 1] + piles[i]
    from functools import lru_cache

    @lru_cache(maxsize=None)
    def dfs(i, m):
        if i + 2 * m >= n:
            return suffix[i]
        best = 0
        for x in range(1, 2 * m + 1):
            best = max(best, suffix[i] - dfs(i + x, max(m, x)))
        return best

    return dfs(0, 1)
function stoneGameII(piles) {
  const n = piles.length;
  const suffix = new Array(n + 1).fill(0);
  for (let i = n - 1; i >= 0; i--) suffix[i] = suffix[i + 1] + piles[i];
  const memo = new Map();
  function dfs(i, m) {
    if (i + 2 * m >= n) return suffix[i];
    const key = i * 200 + m;
    if (memo.has(key)) return memo.get(key);
    let best = 0;
    for (let x = 1; x <= 2 * m; x++)
      best = Math.max(best, suffix[i] - dfs(i + x, Math.max(m, x)));
    memo.set(key, best);
    return best;
  }
  return dfs(0, 1);
}
class Solution {
    int[] suffix;
    Integer[][] memo;
    int n;
    public int stoneGameII(int[] piles) {
        n = piles.length;
        suffix = new int[n + 1];
        for (int i = n - 1; i >= 0; i--) suffix[i] = suffix[i + 1] + piles[i];
        memo = new Integer[n][n + 1];
        return dfs(0, 1);
    }
    int dfs(int i, int m) {
        if (i + 2 * m >= n) return suffix[i];
        if (memo[i][m] != null) return memo[i][m];
        int best = 0;
        for (int x = 1; x <= 2 * m; x++)
            best = Math.max(best, suffix[i] - dfs(i + x, Math.max(m, x)));
        return memo[i][m] = best;
    }
}
class Solution {
    int n;
    vector<int> suffix;
    vector<vector<int>> memo;
    int dfs(int i, int m) {
        if (i + 2 * m >= n) return suffix[i];
        if (memo[i][m] != -1) return memo[i][m];
        int best = 0;
        for (int x = 1; x <= 2 * m; x++)
            best = max(best, suffix[i] - dfs(i + x, max(m, x)));
        return memo[i][m] = best;
    }
public:
    int stoneGameII(vector<int>& piles) {
        n = piles.size();
        suffix.assign(n + 1, 0);
        for (int i = n - 1; i >= 0; i--) suffix[i] = suffix[i + 1] + piles[i];
        memo.assign(n, vector<int>(n + 1, -1));
        return dfs(0, 1);
    }
};
Time: O(n³) Space: O(n²)