「力扣」第 877 題:石子游戲(動態規劃)

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

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章