486. Predict the Winner
Description Submission Solutions
- Total Accepted: 4979
- Total Submissions: 11331
- Difficulty: Medium
- Contributors: sameer13
Given an array of scores that are non-negative integers. Player 1 picks one of the numbers from either end of the array followed by the player 2 and then player 1 and so on. Each time a player picks a number, that number will not be available for the next player. This continues until all the scores have been chosen. The player with the maximum score wins.
Given an array of scores, predict whether player 1 is the winner. You can assume each player plays to maximize his score.
Example 1:
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.
Example 2:
Input: [1, 5, 233, 7] Output: True Explanation: Player 1 first chooses 1. Then player 2 have to choose between 5 and 7. No matter which number player 2 choose, player 1 can choose 233.
Finally, player 1 has more score (234) than player 2 (12), so you need to return True representing player1 can win.
Note:
- 1 <= length of the array <= 20.
- Any scores in the given array are non-negative integers and will not exceed 10,000,000.
- If the scores of both players are equal, then player 1 is still the winner.
Subscribe to see which companies asked this question.
【題目分析】
給定一個正整數數組,選手1從數組的頭部或者尾部選擇一個數,選手2從剩下部分的頭部或尾部選擇一個數,循環往復,直到該數組中的數都被取完。判斷選手1取的數的和值是否大於選手2.
【思路】
兩人依次拿,如果Player1贏,則Player1拿的>Player2拿的。我們把Player1拿的視為"+",把Player2拿的視為"-",如果最后結果大於等於0則Player1贏。
因此對於遞歸來說,beg ~ end的結果為max(nums[beg] - partition(beg + 1, end), nums[end] - partition(beg, end + 1));對於非遞歸來說DP[beg][end]表示即為beg ~ end所取的值的大小(最終與零比較)。
總結:
1. 該問題沒有直接比較一個選手所拿元素的和值,而是把問題轉換為兩個選手所拿元素的差值。這一點很巧妙,是關鍵的一步。
2. 找出遞推表達式:max(nums[beg] - partition(beg + 1, end), nums[end] - partition(beg, end + 1))
3. 通過遞推表達式構造遞歸算法是比較簡單的。但是要構造一個非遞歸的算法難度較大。對於非遞歸算法,首先在dp中賦初始值,這是我們解題的第一步。在這個問題中,我們使用一個二位的數組dp來表示nums數組中任意開始和結束位置兩人結果的差值。
初始的時候,我們僅僅知道對角線上的值。dp[i][i] = nums[i]. 這一點很好理解。
接下來既然是求任意的開始和結束,對於二維數組,那肯定是一個雙層的循環。通過dp中已知的元素和動態規划的遞推表達式,我們就可以構造出我們的需要的結果。非遞歸的方式是從小問題到大問題的過程。
【java代碼——遞歸1(不保存中間狀態)】
1 public class Solution { 2 public boolean PredictTheWinner(int[] nums) { 3 return helper(nums, 0, nums.length-1) >= 0; 4 } 5 6 public int helper(int[] nums, int start, int end) { 7 if(start == end) return nums[start]; 8 else return Math.max(nums[start]-helper(nums, start+1,end), nums[end]-helper(nums, start,end-1)); 9 } 10 }
【java代碼——遞歸2(保存中間狀態)】
1 public class Solution { 2 public boolean PredictTheWinner(int[] nums) { 3 return helper(nums, 0, nums.length-1, new Integer[nums.length][nums.length]) >= 0; 4 } 5 6 public int helper(int[] nums, int start, int end, Integer[][] dp) { 7 if(dp[start][end] == null) { 8 if(start == end) return nums[start]; 9 else return Math.max(nums[start]-helper(nums, start+1,end, dp), nums[end]-helper(nums, start,end-1, dp)); 10 } 11 return dp[start][end]; 12 } 13 }
【java代碼——非遞歸】
1 public class Solution { 2 public boolean PredictTheWinner(int[] nums) { 3 if(nums == null || nums.length == 0) return false; 4 int n = nums.length; 5 int[][] dp = new int[n][n]; 6 7 for(int i = 0; i < n; i++) { 8 dp[i][i] = nums[i]; 9 } 10 11 for(int i = n-2; i >= 0; i--) { 12 for(int j = i+1; j < n; j++) { 13 dp[i][j] = Math.max(nums[i]-dp[i+1][j], nums[j]-dp[i][j-1]); 14 } 15 } 16 17 return dp[0][n-1] >= 0; 18 } 19 }