Skip to main content

Can I Win - Solution & Explanation

MediumMathDynamic ProgrammingBit ManipulationMemoization15 min readAsked at: Amazon, Meta, Google +1
Practice this problem

Problem Statement

In the "100 game" two players take turns adding, to a running total, any integer from 1 to 10. The player who first causes the running total to reach or exceed 100 wins.

What if we change the game so that players cannot re-use integers?

For example, two players might take turns drawing from a common pool of numbers from 1 to 15 without replacement until they reach a total >= 100.

Given two integers maxChoosableInteger and desiredTotal, return true if the first player to move can force a win, otherwise, return false. Assume both players play optimally.

 

Example 1:

Input: maxChoosableInteger = 10, desiredTotal = 11
Output: false
Explanation:
No matter which integer the first player choose, the first player will lose.
The first player can choose an integer from 1 up to 10.
If the first player choose 1, the second player can only choose integers from 2 up to 10.
The second player will win by choosing 10 and get a total = 11, which is >= desiredTotal.
Same with other integers chosen by the first player, the second player will always win.

Example 2:

Input: maxChoosableInteger = 10, desiredTotal = 0
Output: true

Example 3:

Input: maxChoosableInteger = 10, desiredTotal = 1
Output: true

 

Constraints:

  • 1 <= maxChoosableInteger <= 20
  • 0 <= desiredTotal <= 300

Approach Overview

Problem Overview: Two players take turns picking numbers from 1..maxChoosableInteger without reuse. Each picked number adds to a running total. The player who first makes the total reach or exceed desiredTotal wins. The task is to determine if the first player can force a win assuming both players play optimally.

Approach 1: Dynamic Programming with Bitmask (O(n · 2^n) time, O(2^n) space)

Represent the game state using a bitmask where each bit indicates whether a number has already been chosen. A mask of size n uniquely defines which moves remain. From any state, iterate through numbers 1..n; if number i is unused, simulate picking it and check whether the opponent loses from the resulting state. Memoize results for each mask so the same state is never recomputed. The key insight: if any move forces the opponent into a losing state, the current state is winning. This transforms the exponential search tree into a manageable 2^n state DP using Bit Manipulation and Dynamic Programming.

Approach 2: Minimax with Memoization (O(n · 2^n) time, O(2^n) space)

This models the problem as a classic two-player optimal strategy game. Use a recursive minimax search where the current player tries to maximize their chance of winning while the opponent tries to minimize it. At each step, iterate through available numbers and check if choosing one either immediately reaches the target or leads to a state where the opponent cannot win. Cache results using memoization keyed by the bitmask of chosen numbers. Without caching the recursion would explore up to n! paths, but memoization collapses equivalent states to 2^n. This approach highlights the Game Theory reasoning behind the optimal play.

Approach 3: Recursive DP with State Pruning (O(n · 2^n) time, O(2^n) space)

Another formulation stores the remaining total instead of the running sum and recursively tries available numbers. Before recursion, perform quick pruning checks. If the sum of all numbers 1..n is smaller than desiredTotal, winning is impossible. If any single number already reaches the target, the first player wins immediately. During recursion, subtract the chosen number from the remaining total and continue exploring unused numbers using a memo table indexed by the bitmask state. This is essentially top‑down DP with memoization but framed around remaining score rather than accumulated score.

Recommended for interviews: Use the minimax or bitmask DP approach with memoization. Interviewers expect you to recognize the game-state search and compress it using a bitmask. A naive recursive search demonstrates understanding of the game tree, but adding memoization and representing states with bit operations shows strong problem‑solving skill and reduces the complexity to O(n · 2^n).

Approach 1: Dynamic Programming with Bitmask

This approach constructs a dynamic programming solution using bitmasking to represent the state of available numbers. We use a bottom-up strategy to determine if the player can force a winning move given the current pool of available numbers.

This Python solution uses a bottom-up dynamic programming approach with bitmasking. The array `dp` stores win/lose states for each possible combination of used integers, which is traversed and updated iteratively.

Code

Python

Complexity

Time Complexity: O(2^n) where n is the maxChoosableInteger. Space Complexity: O(2^n) due to the storage of states in the dp array.

Try this approach in the editor →

Approach 2: Minimax with Memoization

This approach uses the Minimax algorithm with memoization to evaluate all possible game states, efficiently determining if the first player can guarantee a win. The idea is to explore all possible moves by the current player, then recursively simulate the opponent's optimal response. Memoization is employed to cache results of subproblems to avoid redundant calculations.

The function canIWin decides if a player can win given the constraints. It first checks for immediate game-ending scenarios. The recursive function can_win manages game state using an array to track used numbers, utilizing memoization to store and reuse results of previously computed states.

Code

Python

C

Java

Complexity

The time complexity is O(2^n) due to exploring all possible states, where n is maxChoosableInteger. The space complexity is also O(2^n) because of the memory used in the memoization map.

Try this approach in the editor →

Approach 3: Dynamic Programming

This approach uses dynamic programming to solve the problem. We create a table that keeps track of possible outcomes based on the current state of integers used. It optimizes the recursive solution by considering only valid states and storing their outcomes more directly.

This Python solution employs a dynamic programming strategy with memoization to track used numbers as binary masks. It efficiently avoids recomputation of previously evaluated states, thanks to the lru_cache mechanism.

Code

Python

C++

Complexity

Time complexity is O(2^n) similar to the minimax approach due to bitmasking possibilities, but this is managed efficiently via memoization. Space complexity is also O(2^n).

Try this approach in the editor →

Approach 4: State Compression + Memoization

First, we check if the sum of all selectable integers is less than the target value. If so, it means that we cannot win no matter what, so we directly return false.

Then, we design a function dfs(mask, s), where mask represents the current state of the selected integers, and s represents the current cumulative sum. The return value of the function is whether the current player can win.

The execution process of the function dfs(mask, s) is as follows:

We iterate through each integer i from 1 to maxChoosableInteger. If i has not been selected, we can choose i. If the cumulative sum s + i after choosing i is greater than or equal to the target value desiredTotal, or if the result of the opponent choosing i is losing, then the current player is winning, return true.

If no choice can make the current player win, then the current player is losing, return false.

To avoid repeated calculations, we use a hash table f to record the calculated states, where the key is mask, and the value is whether the current player can win.

The time complexity is O(2^n), and the space complexity is O(2^n). Where n is maxChoosableInteger.

Code

Python

Java

C++

Go

TypeScript

Try this approach in the editor →

Complexity Comparison

ApproachComplexity
Dynamic Programming with Bitmask

Time Complexity: O(2^n) where n is the maxChoosableInteger. Space Complexity: O(2^n) due to the storage of states in the dp array.

Minimax with Memoization

The time complexity is O(2^n) due to exploring all possible states, where n is maxChoosableInteger. The space complexity is also O(2^n) because of the memory used in the memoization map.

Dynamic Programming

Time complexity is O(2^n) similar to the minimax approach due to bitmasking possibilities, but this is managed efficiently via memoization. Space complexity is also O(2^n).

State Compression + Memoization

Detailed Complexity Analysis

ApproachTimeSpaceWhen to Use
Dynamic Programming with BitmaskO(n · 2^n)O(2^n)Best general solution when n ≤ 20 and states can be represented as used-number masks
Minimax with MemoizationO(n · 2^n)O(2^n)When reasoning about optimal play in two-player games
Recursive DP with State PruningO(n · 2^n)O(2^n)Useful when framing the state as remaining target and applying early pruning checks

Video Solution

花花酱 LeetCode 464. Can I Win - 刷题找工作 EP165Hua Hua10,448 views views

Watch 9 more video solutions →

Frequently Asked Questions

Is Can I Win easy or hard?
LeetCode classifies it as Medium, but many candidates find it closer to medium-hard because it requires combining recursion, bitmask state compression, and memoization. Recognizing the 2^n state space is the key insight.
Can I Win Python/Java solution
Implement a recursive function that receives the current bitmask of used numbers and the remaining target. Try every unused number, update the mask with bit operations, and memoize whether that state leads to a win. The same logic works in Python, Java, and C++ with a map or array cache.
How to solve Can I Win in O(n)?
The problem cannot be solved in O(n) because every subset of chosen numbers can represent a different game state. The best known approach explores these states with memoization using bitmask DP, leading to O(n · 2^n) time.
What is the best approach for Can I Win?
The standard solution uses minimax with memoization and a bitmask to represent which numbers are already chosen. Each game state is cached so it is evaluated once. This reduces the search space to about 2^n states, giving O(n · 2^n) time and O(2^n) space complexity.
Is Can I Win asked at Google/Amazon/Meta?
This style of problem appears in interviews at companies like Google, Amazon, and Meta because it tests recursion, memoization, and game theory reasoning. Candidates must model the game state efficiently and avoid recomputing states using bitmask caching.
What data structure is used in Can I Win?
The key structure is a bitmask representing which numbers from 1..n are already used. A hash map or array memo table stores results for each mask so the algorithm does not recompute the same state during recursion.
What is the time complexity of Can I Win?
The optimized solution runs in O(n · 2^n) time. There are at most 2^n possible subsets of chosen numbers, and for each state the algorithm may try up to n candidate moves. Space complexity is O(2^n) for the memoization table.

Ready to solve this problem?

Practice Can I Win with our built-in code editor and test cases.

Practice on FleetCode