1. 程式人生 > 其它 >leetcode486. 預測贏家/877. 石子游戲(區間dp)

leetcode486. 預測贏家/877. 石子游戲(區間dp)

連結:https://leetcode-cn.com/problems/predict-the-winner/
連結:https://leetcode-cn.com/problems/stone-game/

題目

給你一個整數陣列 nums 。玩家 1 和玩家 2 基於這個陣列設計了一個遊戲。

玩家 1 和玩家 2 輪流進行自己的回合,玩家 1 先手。開始時,兩個玩家的初始分值都是 0 。每一回合,玩家從陣列的任意一端取一個數字(即,nums[0] 或 nums[nums.length - 1]),取到的數字將會從陣列中移除(陣列長度減 1 )。玩家選中的數字將會加到他的得分上。當陣列中沒有剩餘數字可取時,遊戲結束。

如果玩家 1 能成為贏家,返回 true 。如果兩個玩家得分相等,同樣認為玩家 1 是遊戲的贏家,也返回 true 。你可以假設每個玩家的玩法都會使他的分數最大化。

用例

示例 1:

輸入:nums = [1,5,2]
輸出:false
解釋:一開始,玩家 1 可以從 1 和 2 中進行選擇。
如果他選擇 2(或者 1 ),那麼玩家 2 可以從 1(或者 2 )和 5 中進行選擇。如果玩家 2 選擇了 5 ,那麼玩家 1 則只剩下 1(或者 2 )可選。
所以,玩家 1 的最終分數為 1 + 2 = 3,而玩家 2 為 5 。
因此,玩家 1 永遠不會成為贏家,返回 false 。
示例 2:

輸入:nums = [1,5,233,7]
輸出:true
解釋:玩家 1 一開始選擇 1 。然後玩家 2 必須從 5 和 7 中進行選擇。無論玩家 2 選擇了哪個,玩家 1 都可以選擇 233 。
最終,玩家 1(234 分)比玩家 2(12 分)獲得更多的分數,所以返回 true,表示玩家 1 可以成為贏家。

提示:

1 <= nums.length <= 20
0 <= nums[i] <= 107

思路

877石子游戲實際上是486預測贏家的特殊情況,兩者的區間dp思路一致
區間dp主要是尋找區間內的最優解
預測贏家,主要判定在區間[0,n-1]之間玩家1和玩家2能取得的最大差值,在[x,y]區間上能取得的最大差值即為max(nums[x]-dp[x+1][y],nums[y]-dp[x][y-1])範圍,區間每縮小一步即為對手操作獲得最高分

class Solution {
public:
    bool PredictTheWinner(vector<int>& nums) {
        int n=nums.size();
        vector<vector<int>>dp(n,vector<int>(n));
        for(int i=0;i<n;++i){
            dp[i][i]=nums[i];
        }
        for(int i=1;i<n;++i){
            int x=0,y=i;
            while(x<n&&y<n){
                dp[x][y]=max(nums[x]-dp[x+1][y],nums[y]-dp[x][y-1]);
                ++x;
                ++y;
            }
        }
        if(dp[0][n-1]>=0)
            return true;
        return false;
    }
};

在石子游戲中由於不存在平局情況,而且每人拿到的石子數相同(石子堆數量為偶數),即先手者一定能取得偶數堆中的最大值和奇數堆中的最大值,所以先手必勝