1. 程式人生 > 其它 >[LeetCode] 1140. Stone Game II 石子游戲之二

[LeetCode] 1140. Stone Game II 石子游戲之二


Alice and Bob continue theirgames with piles of stones. There are a number ofpilesarranged in a row, and each pile has a positive integer number of stonespiles[i]. The objective of the game is to end with the moststones.

Aliceand Bob take turns, with Alice starting first. Initially,M = 1.

On each player's turn, that playercan takeall the stonesin thefirstX

remaining piles, where1 <= X <= 2M. Then, we setM = max(M, X).

The game continues until all the stones have been taken.

Assuming Alice and Bob play optimally, return the maximum number of stones Alicecan get.

Example 1:

Input: piles = [2,7,9,4,4]
Output: 10
Explanation:  If Alice takes one pile at the beginning, Bob takes two piles, then Alice takes 2 piles again. Alice can get 2 + 4 + 4 = 10 piles in total. If Alice takes two piles at the beginning, then Bob can take all three piles left. In this case, Alice get 2 + 7 = 9 piles in total. So we return 10 since it's larger.

Example 2:

Input: piles = [1,2,3,4,5,100]
Output: 104

Constraints:

  • 1 <= piles.length <= 100
  • 1 <= piles[i]<= 104

這道題是石頭遊戲系列的第二道,跟之前那道 Stone Game 不同的是終於換回了 Alice 和 Bob!還有就是取石子的方法,不再是隻能取首尾兩端的石子堆,而是可以取 [1, 2M] 範圍內的任意X堆,M是個變化的量,初始化為1,每次取完X堆後,更新為 M = max(M, X)。這種取石子的方法比之前的要複雜很多,由於X的值非常的多,而且其不同的選擇還可能影響到M值,那麼整體的情況就特別的多,暴力搜尋基本上是行不通的。這種不同狀態之間轉移的問題用動態規劃 Dynamic Programming 是比較合適的,首先來考慮 DP 陣列的定義,題目要求的是 Alice 最多能拿到的石子個數,拿石子的方式是按順序的,不能跳著拿,所以決定某個狀態的是兩個變數,一個是當前還剩多少石子堆,可以通過當前位置座標i來表示,另一個是當前的m值,只有知道了當前的m值,那麼選手才知道能拿的堆數的範圍,所以 DP 就是個二維陣列,其 dp[i][m] 表示的意義在上面已經解釋了。接下來考慮狀態轉移方程,由於在某個狀態時已經知道了m值,則當前選手能拿的堆數在範圍 [1, 2m] 之間,為了更新這個 dp 值,所有x的情況都要遍歷一遍,即在剩餘堆數中拿x堆,但此時x堆必須小於等於剩餘的堆數,即 i + x <= n

,i為當前的位置。由於每個選手都是預設選最優解的,若能知道下一個選手該拿的最大石子個數,就能知道當前選手能拿的最大石子個數了,因為二者之和為當前剩餘的石子個數。由於當前選手拿了x堆,則下個選手的位置是 i+x,且m更新為 max(m,x),所以其 dp 值為 dp[i + x][max(m, x)])。為了快速得知當前剩餘的石子總數,需要建立累加和陣列,注意這裡是建立反向的累加和陣列,其中 sums[i] 表示範圍 [i, n-1] 之和。分析到這裡就可以寫出狀態狀態轉移方程如下:

dp[i][m] = max(dp[i][m], sums[i] - dp[i + x][max(m, x)])

接下來就是一些初始化和邊界定義的問題需要注意的了,dp 陣列大小為 n+1 by n+1,因為選手是可能一次將n堆都拿了,比如 n=1 時,所以 dp[i][n] 是存在的,且需要用 sums[i] 來初始化。更新 dp 時需要用三個 for 迴圈,分別控制i,m,和 x,注意更新從後往前遍歷i和m,因為我們要先更新小區間,再更新大區間。x的範圍要設定為 x <= 2 * m && i + x <= n,前面也講過原因了,最後的答案儲存在 dp[0][1] 中返回即可,參見程式碼如下:


解法一:

class Solution {
public:
    int stoneGameII(vector<int>& piles) {
        int n = piles.size();
        vector<int> sums = piles;
        vector<vector<int>> dp(n + 1, vector<int>(n + 1));
        for (int i = n - 2; i >= 0; --i) {
            sums[i] += sums[i + 1];
        }
        for (int i = 0; i < n; ++i) {
            dp[i][n] = sums[i];
        }
        for (int i = n - 1; i >= 0; --i) {
            for (int m = n - 1; m >= 1; --m) {
                for (int x = 1; x <= 2 * m && i + x <= n; ++x) {
                    dp[i][m] = max(dp[i][m], sums[i] - dp[i + x][max(m, x)]);
                }
            }
        }
        return dp[0][1];
    }
};

我們再來用遞迴加記憶陣列的方式來實現一下,其實核心思想跟上面完全一樣,這裡就不過多的講解了,直接看程式碼吧:


解法二:

class Solution {
public:
    int stoneGameII(vector<int>& piles) {
        int n = piles.size();
        vector<int> sums = piles;
        vector<vector<int>> memo(n, vector<int>(n));
        for (int i = n - 2; i >= 0; --i) {
            sums[i] += sums[i + 1];
        }
        return helper(sums, 0, 1, memo);
    }
    int helper(vector<int>& sums, int i, int m, vector<vector<int>>& memo) {
        if (i + 2 * m >= sums.size()) return sums[i];
        if (memo[i][m] > 0) return memo[i][m];
        int res = 0;
        for (int x = 1; x <= 2 * m; ++x) {
            int cur = sums[i] - sums[i + x];
            res = max(res, cur + sums[i + x] - helper(sums, i + x, max(x, m), memo));
        }
        return memo[i][m] = res;
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/1140


類似題目:

Stone Game


參考資料:

https://leetcode.com/problems/stone-game-ii/

https://leetcode.com/problems/stone-game-ii/discuss/345247/C%2B%2B-DP-(Tabulation)

https://leetcode.com/problems/stone-game-ii/discuss/345230/JavaPython-DP-Solution


LeetCode All in One 題目講解彙總(持續更新中...)