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;
    }
}
相關文章
相關標籤/搜索