# 486 Predict the Winner

題目給一正整數陣列,遊戲規則是player 1和player 2 輪流從數列的左右兩端選一數字,最後數字總和較大者勝利。假設player 1 和2都會用最聰明的方式選擇,問player 1贏的可能性是True還是False

Input: [1, 5, 2]
Output: False
Explanation: Initially, player 1 can choose between 1 and 2. 
If he chooses 2 (or 1), then player 2 can choose from 1 (or 2) and 5. If player 2 chooses 5, then player 1 will be left with 1 (or 2). 
So, final score of player 1 is 1 + 2 = 3, and player 2 is 5. 
Hence, player 1 will never be the winner and you need to return False.

Concept 由於input為正整數陣列,直覺會想開二維dp,dp[i][j]表subarray(i,j)時,player 1的分數,接下來問題就是如何更新每個dp[i][j]。 當player 1在dp[i][j]選了一個數字後,要嘛是選i,要嘛是選j,選了i的話,subarray就變成(i+1, j),選了j的話,subarray就變成(i, j-1)。但是!縮短後的subarray是輪到player2選,下次換player 1選又要再短一點了。因此可得: dp[i][j] = max(num[i] + min(dp[i+2][j], dp[i+1][j-1]), num[j] + min(dp[i+1][j-1], dp[i][j-2]))

中間是min的原因是,player 2 不會讓player 1選到大的。

最後結果會在dp[0][nums.length-1]這格。total - dp[0][nums.length-1] < dp[0][nums.length-1]就代表player 1贏了。

Code

class Solution {
    public boolean PredictTheWinner(int[] nums) {
        int total = 0;
        if(nums == null || nums.length == 0) return true;
        for(int num : nums) {
            total+=num;
        }
        int[][] dp = new int[nums.length][nums.length];
        for(int i=0;i<nums.length;i++) {
            for(int j=i;j>=0;--j) {
                if(i==j) {
                    dp[j][i] = nums[i];
                    continue;
                }
                if(i==j+1) {
                    dp[j][i] = Math.max(nums[j], nums[i]);
                    continue;
                }
                dp[j][i] = Math.max(nums[j] + Math.min(dp[j+2][i], dp[j+1][i-1]), 
                                    //player 2 will only let player 1 select the smaller number among (dp[j+2][i], dp[j+1][i-1])
                                    nums[i] + Math.min(dp[j+1][i-1], dp[j][i-2]));
            }
        }
        return !((total-dp[0][nums.length-1]) > dp[0][nums.length-1]);
    }
}

results matching ""

    No results matching ""