1. 程式人生 > >Leetcode 464.我能贏嗎

Leetcode 464.我能贏嗎

turn desire vat upd 表現 cas current ole 給定

我能贏嗎

在 "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),從而取得勝利.

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

DFS + memorizatoin

通過state保存狀態,即當前選了哪些數

需要註意maxChoosableInteger不會大於20,我們完全可以通過一個32位的整數來表示狀態

例如選擇了1和2,那麽狀態為01 | 10 = 11 = 3(選擇的數為1左移位數-1)

 1 class Solution {
 2     public boolean canIWin(int maxChoosableInteger, int desiredTotal) {
 3         if(desiredTotal <= maxChoosableInteger)
 4             return true;
 5         //Note: n should be <= 32 as int is 32-bit in Java; else it will 1 << 33+ equals 0.
6 int n = maxChoosableInteger; 7 int sum = n * (n + 1) / 2; 8 if(sum < desiredTotal) 9 return false; 10 Boolean[] dp = new Boolean[1 << n]; 11 return canIWin(0, n, desiredTotal, dp); 12 } 13 14 private boolean canIWin(int state, int n, int remain, Boolean[] dp) { 15 if (remain <= 0) { 16 //dp[state] = false; 17 // Base case: 18 return false; 19 } 20 if (dp[state] == null) { 21 dp[state] = false; 22 int mask = 1; 23 //Key Point: take from the tail 24 for(int i = 1; i <= n; i++){ 25 int future = state | mask; 26 //the other can win 27 if (future != state && !canIWin(future, n, remain - i, dp)) { 28 //update current status = true 29 dp[state] = true; 30 break; 31 } 32 mask <<= 1; 33 } 34 } 35 return dp[state]; 36 } 37 }


Leetcode 464.我能贏嗎