Alice and Bob take turns playing a game, with Alice starting first.
Initially, there is a number n
on the chalkboard. On each player's turn, that player makes a move consisting of:
x
with 0 < x < n
and n % x == 0
.n
on the chalkboard with n - x
.Also, if a player cannot make a move, they lose the game.
Return true
if and only if Alice wins the game, assuming both players play optimally.
Example 1:
Input: n = 2 Output: true Explanation: Alice chooses 1, and Bob has no more moves.
Example 2:
Input: n = 3 Output: false Explanation: Alice chooses 1, Bob chooses 1, and Alice has no more moves.
Constraints:
1 <= n <= 1000
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force method for this game is like exploring every single possible move and outcome. We play the game out in our mind step by step, trying every allowed choice at each turn. We continue this process until we find a winning strategy for the first player, or until we've exhausted all possibilities.
Here's how the algorithm would work step-by-step:
def divisor_game_brute_force(number):
def can_win(current_number, is_alice_turn):
# Base case: If number is 0, the other player won
if current_number == 0:
return not is_alice_turn
divisors = []
for possible_divisor in range(1, current_number + 1):
if current_number % possible_divisor == 0:
divisors.append(possible_divisor)
#If no divisors, the current player loses
if not divisors:
return False
# Try all divisors and see if any lead to a win
for divisor in divisors:
next_number = current_number - divisor
# Recursively check if the other player loses with the next number
if not can_win(next_number, not is_alice_turn):
return True
# If no move leads to a win, the current player loses
return False
#Alice is the first to make a move
return can_win(number, True)
The core idea is to determine who wins based on the starting number. We can figure this out without actually playing the game by recognizing a simple pattern. The winner is predictable based on whether the starting number is odd or even.
Here's how the algorithm would work step-by-step:
def divisor_game(number):
# If the starting number is even, Alice wins.
if number % 2 == 0:
return True
# If the number is 1, Alice loses
# If the starting number is odd, Alice loses.
else:
return False
Case | How to Handle |
---|---|
n = 1 | Alice loses immediately as there are no divisors x such that 0 < x < 1, so return false. |
n = 2 | Alice chooses x = 1, n becomes 1, Bob loses; therefore, Alice wins so return true. |
Large values of n | Memoization or dynamic programming is necessary to avoid exponential time complexity from repeated calculations for the same n. |
n is a prime number | Alice can only choose 1, reducing n to n-1, and the game continues depending on n-1. |
n is a power of 2 | This can influence the win/loss pattern; the solution should correctly determine the outcome through the game's rules. |
Recursion depth exceeding limits without memoization | If the approach is recursive, ensure memoization is used to prevent stack overflow errors for large values of n. |
Integer overflow when calculating n - x | The problem statement guarantees n is an integer so integer overflow is not a concern for subtraction given that x < n. |
Time Limit Exceeded (TLE) for large n without optimization | Ensure the solution uses efficient algorithms like dynamic programming or memoization to reduce time complexity. |