LeetCode 464. Can I Win
隨便抽的一題,感覺最後的測資有點沒意思,故意放來卡人家WA的。
題目
設計一個小遊戲,假設給定一個數字N,玩家可以選擇1~N中任意一個數字,加到總和中,使總和超過目標值的人獲勝。每個數字只能被選用一次。
輸入兩個整數maxChoosableInteger和desiredTotal,假設兩個玩家都發揮最佳,如果先手的玩家能贏,則回傳true,否則回傳false。
解法
因為可選的數字N最大只到20,而且每個都只能用一次,很明顯可以用bitmask來表示每個數字的使用狀態。
定義dp(mask,remain):mask為當前可選擇的數字,而remain代表再加上多少數可以獲勝。
玩家可以獲勝的情況有兩種:
- 當前某個可選的數字大於等於remain
- 選擇某個數之後後,使對手無法勝利
所以遍歷每個可用的數字i,若當前數字大於等於remain,直接回傳true;否則將數字i標記為已使用,繼續遞迴下去。
處理完所有可用數字後,若沒有符合的情況,代表無法勝利,只能回傳false。
但是有一個很無聊的測資:
N=5, target=50
1~5全部加起來根本不到50,兩邊玩家根本都不可能贏,要在開頭加上檢查,避免出錯。
class Solution:
def canIWin(self, maxChoosableInteger: int, desiredTotal: int) -> bool:
N=maxChoosableInteger
if N*(N+1)//2<desiredTotal:
return False
@cache
def dp(mask,remain):
for i in range(N):
if not mask&(1<<i) and remain<=(i+1):
return True
if not mask&(1<<i):
newMask=mask|(1<<i)
if not dp(newMask,remain-(i+1)):
return True
return False
return dp(0,desiredTotal)