Question
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.
给出一个包含非负整数的分数的列表。玩家1选择列表最左边的数字或者最右边的数字,然后玩家二选择,以此循环,持续到所有数字都被选择完。一旦用户选择一个数字,这个数字将不能再被选择。分数高者获胜。现在给出一个分数列表,请你预测玩家1是否会赢。每个玩家都会使他的分数最大化。
Example
*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.
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.
Solution
动态规划解。既然每个玩家在选择的时候都会使自己的利益最大化,那么玩家一获胜的条件就是总收益大于玩家二。假设 solve(start, end) 为玩家在nums[start:end]之间的最大收益,那么玩家一首先判断选择列表最左端的数字的收益:nums[start] - solve(start + 1, end) (解释:自己当前选择了最左边的数字,这一轮获得了该数字的分数的收益,那么接下来是对手选择了,solve(start + 1, end) 就是对手在这一轮获得的收益,相减就是玩家一这轮选择列表最左端的数字的收益了),同理选择最右端数字的收益:nums[end] - solve(start, end - 1)。为了保证自己的胜利,玩家一肯定选择收益更大的那个,即max(nums[start] - solve(start + 1, end), nums[end] - solve(start, end - 1))。这样如果最后得到的收益大于0则代表玩家一赢,否则玩家二赢。
# without memories(更易理解,但是不能AC) class Solution(object): def PredictTheWinner(self, nums): """ :type nums: List[int] :rtype: bool """ self.nums = nums return self.solve(0, len(nums) - 1) >= 0 def solve(self, start, end): """ 计算当前选手在nums[start, end]下的收益 """ if start >= end: return 0 if start == end: return self.nums[start] # 如果只有一个数字,那么肯定玩家一赢 return max(self.nums[start] - self.solve(start + 1, end), self.nums[end] - self.solve(start, end - 1)) # 选择收益更大的那个
# with memories class Solution(object): def PredictTheWinner(self, nums): """ :type nums: List[int] :rtype: bool """ self.nums = nums self.memory = {} # 如果大于零则赢 return self.solve(0, len(nums) - 1) >= 0 def solve(self, start_index, end_index): """ 计算当前选手在nums[start_index, end_index]下的收益 """ if (start_index, end_index) not in self.memory: if start_index == end_index: self.memory[(start_index, end_index)] = self.nums[start_index] else: self.memory[(start_index, end_index)] = max(self.nums[start_index] - self.solve(start_index + 1, end_index), self.nums[end_index] - self.solve(start_index, end_index - 1)) return self.memory[(start_index, end_index)]