leetcode 464 我能贏嗎

2021-10-07 21:49:10 字數 3054 閱讀 5204

題目:

在 「100 game」 這個遊戲中,兩名玩家輪流選擇從 1 到 10 的任意整數,累計整數和,先使得累計整數和達到 100 的玩家,即為勝者。

如果我們將遊戲規則改為 「玩家不能重複使用整數」 呢?

例如,兩個玩家可以輪流從公共整數池中抽取從 1 到 15 的整數(不放回),直到累計整數和 >= 100。

給定乙個整數 maxchoosableinteger (整數池中可選擇的最大數)和另乙個整數 desiredtotal(累計和),判斷先出手的玩家是否能穩贏(假設兩位玩家遊戲時都表現最佳)?

你可以假設 maxchoosableinteger 不會大於 20, desiredtotal 不會大於 300。

示例:

輸入:

maxchoosableinteger = 10

desiredtotal = 11

輸出:false

解釋:

無論第乙個玩家選擇哪個整數,他都會失敗。

第乙個玩家可以選擇從 1 到 10 的整數。 如果第乙個玩家選擇 1,那麼第二個玩家只能選擇從 2 到 10 的整數。

第二個玩家可以通過選擇整數 10(那麼累積和為 11 >= desiredtotal),從而取得勝利.。

同樣地,第乙個玩家選擇任意其他整數,第二個玩家都會贏。

這裡主要去理解大佬的**,自己去總結了一下。

a穩贏表示a選了乙個數後,無論b選剩下的哪個數,a都能在最後一步選了某個數後贏了。比如:三個數,目標和為6,a 首先在三個數中任選乙個數,如3,接著b從剩下的數中隨便怎麼選,都不能使累加和達到6,最後a再在剩下的數中選取某個數後累加達到6以上,那麼a就是穩贏的。

對於上述兩個或三個數好理解,但對於少於或等於20個數,如何理解使a在最後一步選取某個數累加到達目標值。

再對上乙個例字進行解釋:在選用兩個數時,比如a選1,b選2;或者a選2,b選1這兩個子問題。可以看到此時都不能達到目標值,也就是此時a和b對1、2選擇的先後順序都不能達到目標值,那麼在未達到目標值之前,我們可以不考慮a和b各自先後選擇了哪些數,只考慮a和b一起選擇了哪些數,還剩下哪些數及剩餘目標值。也就是我們可以不去管或去掉已選擇的1、2兩個數,而是將問題轉為乙個數,目標和為3的子問題,這樣原問題就變成乙個新的子問題了。

針對上述分析,遞迴解決問題會出現重複計算,而我們又不關心數字是被誰選用,也不關心出現的先後順序,只關心數字的組合,所以把每一種組合狀態儲存,下次遇到相同的狀態查表即可。

按照上述思路來分析:首先定義乙個陣列,這個陣列中的每一位表示 desiredtotal 整數集合中某個數是否被選取。每個數只有被選取和沒有被選取這兩種情況,所以定義乙個二進位制位陣列。題目給出最大數不超過20,那麼就定義乙個boolean dp = new boolean[(1<2-1=3,也就是該陣列有22個元素。為什麼要定義這麼多個陣列元素,可以想一下,整數集合中每個元素可以選取與不選,有多少個整數,就有2maxchoosableinteger 種可能的組合情況。

到現在,dp這個陣列的作用還沒有解釋清楚,上面只是說整數集合中整數的個數來定義乙個多大的陣列,那如何能表示整數集合中所有組合的情況。我們這樣相,1對應的二進位第0位,2對應二進位制第1位,3對應二進位制第2位,……,其次,將二進位制轉化為十進位制數,該數對應二進位制位上整數的和,如二進位制110對應的十進位制為6,二進位制位對應的整數為321,這三個整數和也為6。到這裡,可以想到dp陣列如何表示整數集合中整數元素被選取的情況,即用dp陣列索引表示所選整數的累加和減1,而這個累加和又能體現整數元素選取的情況。dp陣列的索引對應整數累加和狀態,該整數累加和狀態對應組合狀態;dp陣列元素的值表示整數組合狀態對應的結果,為true表示該組合狀態已存在並且能贏,直接返回;為false表示該組合狀態已存在並且輸了,直接返回;為空表示還沒出現這種整數組合狀態,是乙個新狀態,需要進行遞迴計算。(注意:這裡定義boolean包裝類型別,而不是基本資料型別,所以每個元素為乙個引用型別,初始為 null)。

**:

public boolean caniwin

(int maxchoosableinteger,

int desiredtotal)

// 若整數集合中所有元素和小於目標和,則平局,返回false。if(

(1+maxchoosableinteger)

*maxchoosableinteger/

2< desiredtotal)

// 考慮每個數字只有兩種情況,所以可以使用狀態壓縮dp,即使用bit位來表示選中狀態。

// 定義狀態陣列dp,索引值表示組合狀態,可以體現哪些整數被選取;

// dp陣列中元素的值有三種情況:

// 1、為null,當前整數組合狀態還沒出現過,需要計算訪問。

// 2、為true,當前整數組合狀態已經出現過,直接查詢返回true。

// 3、為false,當前整數組合狀態已經出現過,直接查詢返回false。

boolean[

] dp =

newboolean[(

1<

];return

recursion

(maxchoosableinteger, desiredtotal,dp,0)

;}// 整數集合中最大值不大於20,所有整數和也不會超過int型別,所以用乙個int整數型別表示狀態。

public boolean recursion

(int maxchoosableinteger,

int desiredtotal,boolean[

] dp,

int state)

// 遍歷每乙個數,得到所用整數組合情況。

for(

int i =

1; i <= maxchoosableinteger; i++)}

} dp[state]

=false

;return

false

;}

leetcode 464 我能贏嗎?

在 100 game 這個遊戲中,兩名玩家輪流選擇從 1 到 10 的任意整數,累計整數和,先使得累計整數和達到 100 的玩家,即為勝者。如果我們將遊戲規則改為 玩家不能重複使用整數 呢?例如,兩個玩家可以輪流從公共整數池中抽取從 1 到 15 的整數 不放回 直到累計整數和 100。給定乙個整數...

leetcode 464 我能贏嗎

參考思路是遍歷每一種可能性,得出必勝的走法。然而,用遞迴會存在很多的重複計算,所以可用動態規劃儲存下計算的狀態,用map儲存,其中int對應current,考慮 所以可以用int來儲存1 20的數字是否使用,比如1,就相當於1 current 即將第一位 置1 以此類推。首先判斷,如果maxchoo...

464 我能贏嗎

在 100 game 這個遊戲中,兩名玩家輪流選擇從 1 到 10 的任意整數,累計整數和,先使得累計整數和達到 100 的玩家,即為勝者。如果我們將遊戲規則改為 玩家不能重複使用整數 呢?例如,兩個玩家可以輪流從公共整數池中抽取從 1 到 15 的整數 不放回 直到累計整數和 100。給定乙個整數...