LintCode刷题——硬币排成线I、II

硬币排成线I:算法

题目描述:数组

n 个硬币排成一条线。两个参赛者轮流从右边依次拿走 1 或 2 个硬币,直到没有硬币为止。拿到最后一枚硬币的人获胜。spa

请断定第一个玩家是输仍是赢?code

样例:blog

n = 1, 返回 true.递归

n = 2, 返回 true.it

n = 3, 返回 false.io

n = 4, 返回 true.class

n = 5, 返回 true.遍历

挑战:

O(1) 时间复杂度且O(1) 存储。

算法分析:

本题一我的能够拿1个或者2个,若是输入的n符合条件,为了确保第一我的拿必定可以赢,则对拿法必定要有要求:第一我的在第一次拿以后必定要保证剩下的物品数量为3的倍数,接下来不管第二我的怎么拿,第一我的仍是能把剩下的物品数量控制在3的倍数,所以第一我的必定可以确保本身拿到最后一枚硬币并获胜。所以对于输入的数n,n%3=0时为false,不然为true;
代码(应当是LintCode的最简代码了吧):
public class Solution {
    /*
     * @param n: An integer
     * @return: A boolean which equals to true if the first player will win
     */
    public boolean firstWillWin(int n) {
        // write your code here
        return n%3!=0;
    }
}

硬币排成线II:

题目描述:

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

请断定第一个玩家是输仍是赢?

样例:

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

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

算法描述:

对于本题,其判断输赢的标准是拿到硬币总价值的高低,有两种解法:动态规划或者递归遍历出全部状况并判断每种状况。然而,对于递归实现我以为是比较无脑且费时的,并且对于本题必定会TLE。

这里介绍一下动态规划的解法:

①要判断第一个玩家是否可以赢得比赛,咱们就须要对玩家的不一样拿法进行分析与判断,获得利润最大的那种拿法。由于针对玩家1的每一种拿法,玩家2会想出本身的拿法让玩家1接下去的获利最小,而对玩家1,就是要保证当前的拿法可以使剩下的硬币获利最大,所以咱们须要从后往前经过记录后续拿法的最优解来进行动态规划。

②创建数组DP[i]表示拿第i个硬币到第n个硬币所能得到的最大利润;

③对于玩家拿到第i个硬币时,玩家拿硬币还是从左往右拿。所以他有两种选择,仅拿第i个硬币或者拿第i个与第i+1个硬币,这两种拿法均会产生一个价值做为DP[i]的值;由于咱们是从后往前进行动态规划,咱们知道后续的结果,所以咱们知道怎样的拿法会使得最终结果更好;

④第二个玩家在咱们作出选择后也会对第一个玩家的利益进行限制,例如当第一个玩家拿第i个硬币时,他能够拿第i+1个或拿第i+一、i+2个硬币,可是他会对的结果进行判断,保证第一个玩家的获利达到最小,即选择DP[i+2]和DP[i+3]中的最小值来决定本身是拿一个仍是拿两个;

综上,动态规划表达式为:DP[i] = max{nums[i]+min{DP[i+2],DP[i+3]} ,  nums[i]+nums[i+1]+min{DP[i+3],DP[i+4]} };

代码:

public class Solution {
    /*
     * @param values: a vector of integers
     * @return: a boolean which equals to true if the first player will win
     */
    public boolean firstWillWin(int[] values) {
        // write your code here
        int n = values.length;
        if(values==null||n==0){
            return false;
        }
        if(n<=2){
            return true;
        }
        int[] DP = new int[n+1];
        DP[n]=0;
        DP[n-1]=values[n-1];
        DP[n-2]=values[n-1]+values[n-2];
        DP[n-3]=values[n-2]+values[n-3];
        for(int i=n-4;i>=0;i--){
            //咱们取一个数或取两个数
            DP[i]=values[i]+Math.min(DP[i+2],DP[i+3]);
            DP[i]=Math.max(DP[i],values[i]+values[i+1]+Math.min(DP[i+3],DP[i+4]));
        }
        int sum=0;
        for(int i:values){
            sum+=i;
        }
        return DP[0]*2>sum;
    }
}
相关文章
相关标签/搜索