Stone Game VII
update Jun 11, 2021

Basic Idea:
Stone Game是一个典型的DP系列,但是我一直都没有很好的整理过。
对于这道题来说,先动手的玩家一定赢,而要求的就是以当前玩家的视角,在两个玩家都做出最优选择的情况下能够比对方多出来的分数。我们注意到对于输入数组 [5,3,1,4,2]
, 选择5或者选择2会分别留给下一个玩家不同的局面,而对面玩家同样需要保证能从下局开始获得尽可能大的优势。所以这里其实有一个递归的做法,即下面的dfs解法。另一种做法是bottom up DP,从只有一个数字开始到两个相邻的数字,然后到三个相邻数字,直到推导出整个数组。
这里有一个比较抽象的地方,类似于一点 min max 算法的思路,就是 最终分数差距 = 本局得分 - 对手从剩下数字中最优选择继续游戏导致的对手能得到的最大差距
。
DP 解法

class Solution {
public int stoneGameVII(int[] stones) {
int[] prefixSum = new int[stones.length + 1];
for (int i = 0; i < stones.length; ++i) {
prefixSum[i + 1] = prefixSum[i] + stones[i];
}
int[][] dp = new int[stones.length][stones.length];
for (int i = 0; i < stones.length; ++i) {
dp[i][i] = 0;
}
for (int l = 1; l <= stones.length; ++l) {
for (int i = 0; i + l < stones.length; ++i) {
int j = i + l;
dp[i][j] = Math.max(
prefixSum[j + 1] - prefixSum[i + 1] - dp[i + 1][j],
prefixSum[j] - prefixSum[i] - dp[i][j - 1]);
}
}
// for (int i = 0; i < stones.length; ++i) {
// System.out.println(Arrays.toString(dp[i]));
// }
return dp[0][stones.length - 1];
}
}
DFS with Cache 解法
class Solution {
public int stoneGameVII(int[] stones) {
int[][] cache = new int[1000][1000];
for (int i = 0; i < cache.length; ++i) {
Arrays.fill(cache[i], Integer.MAX_VALUE);
}
return getMaxDiff(stones, 0, stones.length - 1, cache);
}
private int getMaxDiff(int[] arr, int left, int right, int[][] cache) {
if (left == right) return 0;
if (cache[left][right] != Integer.MAX_VALUE) {
return cache[left][right];
}
int maxDiff = Math.max(
sum(arr, left, right - 1) - getMaxDiff(arr, left, right - 1, cache),
sum(arr, left + 1, right) - getMaxDiff(arr, left + 1, right, cache)
);
cache[left][right] = maxDiff;
return maxDiff;
}
private int sum(int[] arr, int left, int right) {
int ret = 0;
for (int i = left; i <= right; ++i) {
ret += arr[i];
}
return ret;
}
}
Last updated