地址:https://leetcode-cn.com/problems/stone-game/
方法一:记忆化递归
Java 代码:
import java.util.Arrays;
public class Solution {
public boolean stoneGame(int[] piles) {
int len = piles.length;
int[][] memo = new int[len][len];
for (int i = 0; i < len; i++) {
Arrays.fill(memo[i], -99999999);
memo[i][i] = piles[i];
}
return stoneGame(piles, 0, len - 1, memo) > 0;
}
/**
* 计算子区间 [left, right] 里先手能够得到的分数
*
* @param piles
* @param left
* @param right
* @return
*/
private int stoneGame(int[] piles, int left, int right, int[][] memo) {
if (memo[left][right] != -99999999) {
return memo[left][right];
}
if (left == right) {
return piles[left];
}
int res = Math.max(piles[left] - stoneGame(piles, left + 1, right, memo),
piles[right] - stoneGame(piles, left, right - 1, memo));
memo[left][right] = res;
return res;
}
}
方法二:动态规划
Java 代码:
public class Solution {
public boolean stoneGame(int[] piles) {
int len = piles.length;
int[][] dp = new int[len][len];
for (int i = 0; i < len; i++) {
dp[i][i] = piles[i];
}
// 注意顺序,新值一定要参考旧址
for (int k = 2; k <= len; k++) {
// i 表示左边界
for (int i = 0; i < len - k + 1; i++) {
// j 表示右边界
int j = i + k - 1;
dp[i][j] = Math.max(piles[i] - dp[i + 1][j], piles[j] - dp[i][j - 1]);
}
}
return dp[0][len - 1] > 0;
}
}
方法三:动态规划(状态压缩)
Java 代码:
public class Solution {
public boolean stoneGame(int[] piles) {
int len = piles.length;
int[] dp = new int[len];
for (int i = 0; i < len; i++) {
dp[i] = piles[i];
}
// 注意顺序,新值一定要参考旧址
for (int k = 2; k <= len; k++) {
// i 表示左边界
for (int i = 0; i < len - k + 1; i++) {
// j 表示右边界
int j = i + k - 1;
dp[i] = Math.max(piles[i] - dp[i + 1], piles[j] - dp[i]);
}
}
return dp[0] > 0;
}
}
方法四:数学解
Java 代码:
public class Solution {
// Alex 总是赢得 2 堆时的游戏
// 通过一些努力,我们可以获知他总是赢得 4 堆时的游戏
// 反推
// 如果 Alex 最初获得第一堆,她总是可以拿第三堆
// 如果他最初取到第四堆,她总是可以取第二堆。
// [重点]
// 比较:第一 + 第三,第二 + 第四 中的至少一组是更大的,所以她总能获胜
public boolean stoneGame(int[] piles) {
return true;
}
}