Predict the Winner

update Jul,30 2017 20:44

LeetCodearrow-up-right

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.

Basic Idea:

这里arrow-up-right是一个很好的分析文章,讲了使用minMax方法的思路。 这里arrow-up-right 是ucla关于Alpha-Beta 剪枝算法的讲义,非常好。

先概括说一下思路 这道题目属于一个双方博弈的零和问题,可以使用博弈树模型来理解其过程。最intuitive的解法是用minMax算法recursively地对双方依次计算所有的下一个状态,并为双方取所有结果可能的最大值,最终再比较两方player1 和 player2 的最大值。代码如下:

我们觉得上面的代码太复杂,想到:player 1 获胜就是 player1.score > player2.score 也就是 player1.score - player2.score > 0,基于这种思路,我们可以给整个局势的结果统一制定评分标准,就是总分大于等于0,则player1获胜。每次player1的得分记为正数,player2 的分数则为负数。然后用一个 int player 来标注,1 表示 player1,-1 表示 player2. 代码如下:

接下来,我们还可以应用 Alpha-Beta Pruning 算法对上面的negaMax进行优化。详见前面的链接。 在这里,我们对 minMax() 函数传入每层选择的数字,这样到了出口我们就会知道这条path的总分,进而进行剪枝就会变得方便。 !![](/assets/Screen Shot 2017-08-01 at 10.45.45 PM.png) Java 代码如下:

Python Code:

经过测试: 应用Alpha-Beta Pruning 之后,时间复杂度变为普通minMax的多项式低阶。而根据wiki,平均应为普通minMax方法的 3/4 次方。比较符合。

Dp Solution:

最快的方法还是使用memoization,避免了大量的重复工作,将时间复杂度缩减到O(n^2)。

解释: 可以这样理解,这里的dfs函数的定义为: