The Open the Lock problem is a well-known interview question that helps build intuition around shortest-path problems. It looks simple at first, but quickly becomes tricky once you account for deadends and repeated states. Many candidates try to reason about moves locally, only to realize that a systematic approach is required. This problem is a great way to understand how breadth-first search can be used to explore all valid possibilities while guaranteeing the minimum number of moves.
Problem statement
You’re given a lock with four circular wheels, each labeled with digits from '0' to '9'. The lock starts at the combination "0000". In one move, you can rotate any single wheel one step forward or backward, with wrap-around behavior (for example, '9' → '0' and '0' → '9').
You’re also given a list of deadends. If the lock ever shows one of these combinations, it becomes stuck and can no longer be turned. Given a target combination, your task is to return the minimum number of moves required to open the lock, or -1 if it is impossible.
At first glance, this may seem like a simple transformation problem. However, because each move creates multiple new states and deadends block progress, the real challenge is finding the shortest path without revisiting states or getting stuck.
Constraints:
- 1 <=
deadends.length<= 500 deadends[i].length== 4target.length== 4- target will not be in the list
deadends. targetanddeadends[i]consist of digits only.
Examples
| Input (deadends, target) | Output | Explanation |
| [“1111″,”1211″,”2111″,”1121”], “2222” | 8 | One valid path carefully avoids deadends and reaches the target in 8 moves. |
| [“9999”], “0001” | 1 | Rotate the last wheel forward once from “0000” to “0001”. |
| [“1000″,”9000″,”0100″,”0900″,”0010″,”0090″,”0001″,”0009”], “5555” | -1 | All possible paths toward the target are blocked by deadends. |
| [“1234”], “0000” | 0 | The lock already starts at the target state, so no moves are needed. |
Why enumerating all possibilities doesn’t scale
A naive approach might try all possible sequences of wheel rotations until the target is reached. However, each lock state can generate up to 8 neighboring states (4 wheels x 2 directions), and the total number of possible combinations is 104.
Without a systematic strategy, this leads to:
- Repeated exploration of the same states
- Exponential growth in possible paths
- Inefficient handling of
deadends
To solve this efficiently, we need a method that explores states level by level, avoids revisiting states, and guarantees the shortest path.
Optimized approach using Breadth-First Search
This problem can be modeled as a graph traversal problem:
- Each lock combination is a node
- An edge exists between two nodes if one move transforms one combination into the other
Since every move has the same cost (one turn), breadth-first search (BFS) is the ideal approach. BFS explores all states reachable in k moves before moving on to k + 1 moves, ensuring that the first time we reach the target is with the minimum number of moves.
Why breadth-first search works well here
The state space is finite and reasonably small (at most 10,000 combinations). BFS efficiently explores this space while guaranteeing optimal results.
This makes the approach:
- Correct: Always finds the minimum number of moves
- Efficient: Avoids unnecessary revisits
- Predictable: Bounded time and space usage
Step-by-step algorithm
The following algorithmic steps describe how to open the lock efficiently:
- Convert the
deadendslist into a set for fast lookup. - If the starting state
"0000"is a deadend, return-1. - Initialize a queue with the starting state
"0000"and move count0. - Maintain a
visitedset to track explored combinations. - While the queue is not empty:
- Dequeue the current state and its move count.
- If the current state equals the target, return the move count.
- For each of the 4 wheel positions:
- Rotate the wheel one step forward and backward to generate new states.
- If a generated state is not a deadend and not visited:
- Add it to the queue with move count + 1.
- Mark it as visited.
- If the target is never reached, return
-1.
To better understand the algorithm, let’s walk through an illustration example below.
Python implementation
Let’s look at the code for the solution we just discussed.
Time complexity
The time complexity of this solution is 104. Each possible lock combination is visited at most once, and each visit generates a constant number of neighboring states.
Space complexity
The space complexity of this solution is 104. The queue and visited set may store all possible combinations in the worst case.
Edge cases
- Starting state is a deadend
- Example:
deadends = ["0000"]→ return-1.
- Example:
- Target is the starting state
- Example:
target = "0000"→ return0.
- Example:
- Target completely blocked by deadends
- All paths to the target pass through deadends.
Common pitfalls
- Using DFS instead of BFS: Depth-first search does not guarantee the shortest path.
- Forgetting to track visited states: Leads to infinite loops or redundant work.
- Incorrect wrap-around logic: Digits must wrap correctly from
'9'to'0'and'0'to'9'.