地址: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;
}
}