題目
愛麗絲和鮑勃一起玩遊戲,他們輪流行動。愛麗絲先手開局。
最初,黑闆上有一個數字 N 。在每個玩家的回合,玩家需要執行以下操作:
- 選出任一 x,滿足 0 < x < N 且 N % x == 0 。
-
用 N - x 替換黑闆上的數字 N 。
如果玩家無法執行這些操作,就會輸掉遊戲。
隻有在愛麗絲在遊戲中取得勝利時才傳回 True,否則傳回 false。假設兩個玩家都以最佳狀态參與遊戲。
示例 1:
輸入:2
輸出:true
解釋:愛麗絲選擇 1,鮑勃無法進行操作。
示例 2:
輸入:3
輸出:false
解釋:愛麗絲選擇 1,鮑勃也選擇 1,然後愛麗絲無法進行操作。
來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/divisor-game
思路
這個題可以用歸納法和動态規劃法來接。先看下動态規劃法。
動态規劃
将所有的小于等于 N (包含N)的解都找出來,可以基于前面的解來推後面的。
當
dp[i]==False
,說明愛麗絲會輸,反之說明會赢。要想愛麗絲赢,就要找到一個約數,使得愛麗絲取時為
True
,并且重新整理後的數為
False
。
class Solution(object):
def divisorGame(self, N):
"""
:type N: int
:rtype: bool
"""
dp = {} #True代表愛麗絲赢,False代表愛麗絲輸
dp[2] = True
dp[1] = False
import math
for i in range(3,N+1):#需要包含N的情況
dp[i] = False
for j in range(1,int(math.sqrt(i))): #限定j的取值範圍
if i % j == 0 and dp[i - j] == False: # 如果 選出任一j,滿足 i % j == 0,且下一個數字為False
dp[i] = True #找得到這麼一個j,說明i是可以獲勝的
break
return dp[N]
歸納法
- 假設
,愛麗絲無解(選出的值N = 1
必須x
),直接失敗;0 < x < N
- 假設
,愛麗絲可以選擇N = 2
,鮑勃x = 1
,無解,愛麗絲獲勝;N = 2 - 1 = 1
- 假設
,愛麗絲隻可以選擇N = 3
,鮑勃x=1
,參考上面N = 3 - 1 = 2
,此時鮑勃獲勝N=2
- 假設
,愛麗絲可以選擇N = 4
使得鮑勃遇到x = 1
的情況,參考上面,則愛麗絲獲勝;N = 3
class Solution(object):
def divisorGame(self,int N):
return N % 2 == 0