Command Palette

Search for a command to run...

Problem 21.4 · Breadth-First SearchMedium

Open the Lock

What it teaches: BFS over states you generate on the fly, with forbidden states pre-marked as visited.

Practise it on judges as “Open the Lock”.

The problem

A lock has 4 wheels with digits 0–9, starting at "0000". A move turns one wheel one step (9 wraps to 0 and back). The lock jams on any combination in deadends. Return the fewest moves to reach target, or −1.

Example 1

Input: deadends = [0201,0101,0102,1212,2002], target = "0202"
Output: 6

Constraints

  • 1 ≤ deadends ≤ 500
  • target is not in deadends

Pattern clues in the wording

  • → Fewest moves between states
  • → Each state has a small fixed set of moves

These clues point to Graph BFS: Explore from a start node in rings of increasing distance using a queue and a visited set.

Stuck? Take one hint at a time

Solution.java · starter
import java.util.*;

class Solution {
    public int openLock(String[] deadends, String target) {
        return -1;
    }
}

Write your solution locally or in your editor for now. The in-browser runner (Java first, then Python, C++ and more) will run these tests right here.

Test cases

#InputExpected
1
deadends = ["0201","0101","0102","1212","2002"]
target = "0202"
6
2
deadends = ["8888"]
target = "0009"
1
3
deadends = ["8887","8889","8878","8898","8788","8988","7888","9888"]
target = "8888"
-1

+ 1 hidden test the code runner will check

From slow to fast

Approaches

1

BFS over combinations

Time O(10⁴ × 8) Space O(10⁴)

Level-order BFS from "0000". For each state, turn each wheel +1 and −1 (as +9 mod 10). Skip seen states.

Approach 1
import java.util.*;

class Solution {
    public int openLock(String[] deadends, String target) {
        Set<String> seen = new HashSet<>(Arrays.asList(deadends));
        if (seen.contains("0000")) return -1;
        Deque<String> q = new ArrayDeque<>();
        q.offer("0000");
        seen.add("0000");
        for (int steps = 0; !q.isEmpty(); steps++) {
            for (int size = q.size(); size > 0; size--) {
                String s = q.poll();
                if (s.equals(target)) return steps;
                char[] c = s.toCharArray();
                for (int i = 0; i < 4; i++) {
                    char orig = c[i];
                    for (int d : new int[]{1, 9}) {
                        c[i] = (char) ('0' + (orig - '0' + d) % 10);
                        String t = new String(c);
                        if (seen.add(t)) q.offer(t);
                    }
                    c[i] = orig;
                }
            }
        }
        return -1;
    }
}

Verdict: The state space is small.

Before you submit

Edge cases and common mistakes

Test these inputs

  • "0000" is a deadend
  • Target is "0000" (0 moves)
  • Target surrounded by deadends

Mistakes people make

  • Using (digit − 1) % 10, which is −1 for 0 in Java (add 9 instead).

Interview

Follow-up questions

How much does bidirectional BFS help here?