The Problem

You have a lock in front of you with 4 circular wheels. Each wheel has 10 slots: '0', '1', '2', ..., '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 dead ends, meaning if the lock displays any of these codes, the wheels of the lock will stop turning and you cannot open it.

Given a target representing the value of the wheels when the lock is unlocked, return the minimum total number of turns required to open the lock, or -1 if it is impossible.

Interactive Visualization

Speed:
Lock Dials โ€” Current Combination: 0000
Code
fun openLock(deadends: Array<String>, target: String): Int {    val dead = deadends.toHashSet()    if ("0000" in dead) return -1    val queue: ArrayDeque<Pair<String, Int>> = ArrayDeque()    queue.add("0000" to 0)    val visited = mutableSetOf("0000")    while (queue.isNotEmpty()) {        val (combo, turns) = queue.removeFirst()        if (combo == target) return turns        for (i in 0 until 4) {            val d = combo[i] - '0'            for (nd in intArrayOf((d+1)%10, (d+9)%10)) {                val new = combo.substring(0,i) + nd + combo.substring(i+1)                if (new !in visited && new !in dead) {                    visited.add(new)                    queue.add(new to turns + 1)    }   }   }   }    return -1 }
Status
0
Turn
1
Queue Size
1
Visited
0
Deadends Hit
Press Step or Play to begin.
Queue (front โ†’ back)
Log

How It Works

Key Insight

Think of each 4-digit combination as a node in a graph, and each single-dial turn as an edge connecting two nodes. There are 10,000 possible combinations (0000-9999), and each node has exactly 8 neighbors (4 dials x 2 directions). Finding the minimum turns is equivalent to finding the shortest path in an unweighted graph -- the classic BFS problem.

The Algorithm

  • Initialize: Convert deadends to a set for O(1) lookup. If "0000" is a deadend, return -1 immediately.
  • BFS Setup: Start with "0000" in the queue at distance 0. Mark it visited.
  • Explore: Dequeue a combination. If it matches the target, return the turn count.
  • Generate neighbors: For each of the 4 dial positions, try turning +1 and -1 (wrapping 9 to 0 and 0 to 9).
  • Filter: Only enqueue neighbors that are not visited and not deadends.
  • Repeat until the target is found or the queue is empty (return -1).

Complexity

Time O(10^N * N^2 + D)
Space O(10^N + D)

Where N = 4 (number of dials) and D is the number of deadends. In the worst case, BFS visits all 10,000 combinations. Each combination generates 8 neighbors, and creating each neighbor string takes O(N) time. The visited set and queue can hold up to 10^N entries.