395. 硬币排成线 II(javascript)

题目

395. 硬币排成线 II
有 n 个不同价值的硬币排成一条线。两个参赛者轮流从左边依次拿走 1 或 2 个硬币,直到没有硬币为止。计算两个人分别拿到的硬币总价值,价值高的人获胜。

请判定 第一个玩家 是输还是赢?

样例
给定数组 A = [1,2,2], 返回 true.

给定数组 A = [1,2,4], 返回 false.

  

思路

了解到这是一道博弈题,因为你要知道你拿一个合适还是两个合适。根据题目意思,是两个都是同样很聪明的两个人,知道拿一个还是两个是最优解,唯一区别是顺序--谁先谁后。

那么先分情况:

在n <= 2 时,palyer1 直接拿走2个就是最优解

在n = 3时,player1 先拿2个,留1个给player2,2个都是最优解

在n >= 4时,这种情况比较复杂,但是操作无非就是拿一个或者拿两个。正推思维比较难思考的,不妨试试用逆推,i代表我们从第i个硬币开始算起,len为硬币的长度。

假设我们从硬币排列的最左端开始算起,那么i=len,没有硬币可以选择。

假设我们从硬币排列的最左端前1列开始算起,那么i=len-1,有1个硬币可以选择,根据上面情况分析,palyer1 直接拿走1个就是最优解

假设我们从硬币排列的最左端前2列开始算起,那么i=len-2,有2个硬币可以选择,根据上面情况分析,palyer1 直接拿走2个就是最优解

假设我们从硬币排列的最左端前3列开始算起,那么i=len-3,有3个硬币可以选择,根据上面情况分析,player1 先拿2个,留一个给player2,两个都是最优解

这种假设到我们从硬币排列的最左端前4列开始算起,player1开始决定拿一个还是两个就要分情况了。先给硬币标上顺序ABCD(从左往右)

a情况:

player1决定拿1个硬币即硬币A,还剩下3个硬币分别为BCD,player2也有两种选择,拿一个还是拿两个,那他肯定会留下一个给player1最小的值。根据我们上面分的情况,n=3情况下player2会拿走2个硬币即BC,那么player1硬币面值为A+D

b情况:

player1决定拿2个硬币即硬币AB,还剩下2个硬币分别为CD,player2也有两种选择,拿一个还是拿两个,那他肯定会留下一个给player1最小的值。根据我们上面分的情况,n=2情况下player2会拿走2个硬币即CD,那么player1硬币面值为A+B

 

到这里我们可以发现,这种状态可以一直延续,前后相关,便想到动态规划(不懂自行google),我们先建立一维表格arr,arr[i]表示从硬币第i列算起(不包括i列),到硬币 终点player1所获得硬币的最大面值。比如arr[len]表示硬币的最后一列算起,player1没有硬币可以选择,所以为0。那么arr[0]表示从硬币第0列算起,到达硬币终点player1所获得硬币的最大面值,即为我们所求。

arr[i] = max(a情况,b情况) 

其中,a情况 = 当前player1所拿的1枚硬币面值+min(arr[i+2],arr[i+3]) 注意,arr[i+2] 是player2拿1枚硬币后player1所能获得硬币最大面值,arr[i+3] 是player2拿2枚硬币后player1所能获得硬币最大面值

其中,b情况 = 当前player1所拿的2枚硬币面值+min(arr[i+3],arr[i+4]) 注意,arr[i+3] 是player2拿1枚硬币后player1所能获得硬币最大面值,arr[i+4] 是player2拿2枚硬币后player1所能获得硬币最大面值

总之,这个过程通过逆推不断给arr这个一维表格填充数值,arr可以一直计算到arr[0]。

代码

/**
 * @param values: a vector of integers
 * @return: a boolean which equals to true if the first player will win
 */
const firstWillWin = function (values) { 
    //数组长度
    var len = values.length;
    //注意这里要加一,因为算进了arr[0]
    var arr = new Array(len + 1);

if(len <= 2) { return true; } arr[len] = 0; arr[len-1] = values[len-1]; arr[len-2] = values[len-2] + values[len-1]; arr[len-3] = values[len-3] + values[len-2]; if (len >= 4) { for(var i = len-4;i>=0;i--) { arr[i] = Math.max(values[i]+Math.min(arr[i+2],arr[i+3]), values[i]+values[i+1]+Math.min(arr[i+3], arr[i+4])); } }

posted @ 2018-07-27 02:32  chobyn  阅读(226)  评论(0)    收藏  举报