Community Problem
Open the Lock
Difficulty: Medium
Find the minimum wheel turns to open a 4-digit combination lock while avoiding deadend states.
Open the Lock
Find the minimum wheel turns to open a 4-digit combination lock while avoiding deadend states.
By @ezb1981
February 5, 2026
·
Updated May 18, 2026
1,003 views
6
4.4 (10)
I had this on a Pinterest L4 onsite, and the conversation that mattered came AFTER the BFS: "why is this not Dijkstra?" The right answer (every move costs 1, so BFS dominates Dijkstra by a log factor) was the actual signal. The catalog covers BFS over grids and strings, but it skipped this state-space BFS where the state is a numeric tuple and the deadend list shrinks the graph.
Open the Lock
You have a lock in front of you with 4 circular wheels. Each wheel has 10 slots: '0' through '9'. The wheels can rotate freely and wrap around: for example we can turn '9' to be '0' or '0' to be '9'. Each move consists of turning one wheel one slot.
The lock initially starts at '0000', a string representing the state of the 4 wheels.
You are given a list of deadends (strings), meaning if the lock displays any of these codes, the wheels of the lock will stop turning and you will be unable to open it.
Given a target representing the value of the wheels that will unlock the lock, return the minimum total number of turns required to open the lock, or -1 if it is impossible.
Examples
Example 1:
- Input:
deadends = ["0201", "0101", "0102", "1212", "2002"],target = "0202" - Output:
6 - Explanation: A valid path:
0000 -> 1000 -> 1100 -> 1200 -> 1201 -> 1202 -> 0202. Six turns.
Example 2:
- Input:
deadends = ["8888"],target = "0009" - Output:
1 - Explanation: Turn the last wheel from
'0'to'9'. One turn.
Example 3:
- Input:
deadends = ["8887", "8889", "8878", "8898", "8788", "8988", "7888", "9888"],target = "8888" - Output:
-1 - Explanation: All neighbors of
8888are deadends, so the target is unreachable.
Example 4:
- Input:
deadends = [],target = "0000" - Output:
0 - Explanation: The starting state is already the target.
Constraints
0 <= deadends.length <= 500.deadends[i].length == 4.target.length == 4.targetis not in the list ofdeadends.targetanddeadends[i]consist of digits only.
Follow-up
The state space has 10^4 = 10000 codes, with each having 8 neighbors (each of 4 wheels turning either way). Two-way BFS (one frontier from 0000, one from target) cuts the search by roughly the square root of the state space; great for tight loops but unnecessary at this scale.
Solution
Hints
Solution Walkthrough
Approach: BFS Over Lock States (O(10^4) time, O(10^4) space)
State space: every 4-digit code from "0000" to "9999". Edges: any two states that differ by +1 or -1 (modulo 10) on exactly one wheel. BFS from "0000" gives the minimum number of turns to reach target.
Algorithm
- Reject up front if
"0000"is indeadends. - If
target == "0000", return0. - BFS:
visited = {"0000"}; queue starts with"0000"at step 0.- For each dequeued state, generate 8 neighbors (each of 4 wheels turning up or down with mod-10 wrap).
- Skip neighbors that are in
deadendsor already visited. - Return the current step count + 1 the moment a neighbor equals
target.
- If BFS exhausts, return
-1.
Why It Works
BFS over an unweighted graph yields shortest-path distances. The wrap-around ('9' + 1 = '0', '0' - 1 = '9') is critical: a wheel can be turned in EITHER direction, so each state truly has 8 neighbors. Without the wrap, the search would be a tree on [0..9]^4 with the wrong neighbor structure and would overestimate distances near the digits 0 and 9.
Complexity
Sample
start=0000, deadends={0201, 0101, 0102, 1212, 2002}, target=0202
BFS from 0000:
level 1: 1000, 9000, 0100, 0900, 0010, 0090, 0001, 0009 (no dead)
...
level 6: 0202 reached via 0000 -> 1000 -> 1100 -> 1200 -> 1201 -> 1202 -> 0202Metric Value
Time O(10^4) at most, since the state space is bounded
Space O(10^4) for visited and the BFS queuePitfalls
- Forgetting wrap. A common bug is to skip a state when the digit is at
'9'(turning up) or'0'(turning down). The mod-10 wrap is part of the problem. - Ignoring
'0000'as a deadend. If"0000"itself is indeadends, the answer is-1regardless of target. - Returning the wrong distance for the start. When
target == "0000", return0, not1or-1.
Solution Code
