Open the Lock

medium array hash set string bfs

Problem

A 4-wheel combination lock starts at "0000". Each move turns one wheel up or down by one (with wraparound 0↔9). Given a list of forbidden deadend states, return the minimum moves needed to reach target, or −1 if impossible.

Inputdeadends = ["0201","0101","0102","1212","2002"], target = "0202"
Output6
A shortest sequence is 0000 → 1000 → 1100 → 1200 → 1201 → 1202 → 0202.

from collections import deque

def open_lock(deadends, target):
    dead = set(deadends)
    if "0000" in dead:
        return -1
    if target == "0000":
        return 0
    q = deque([("0000", 0)])
    seen = {"0000"}
    while q:
        s, d = q.popleft()
        for i in range(4):
            for delta in (-1, 1):
                nd = (int(s[i]) + delta) % 10
                nxt = s[:i] + str(nd) + s[i+1:]
                if nxt == target:
                    return d + 1
                if nxt in dead or nxt in seen:
                    continue
                seen.add(nxt)
                q.append((nxt, d + 1))
    return -1
function openLock(deadends, target) {
  const dead = new Set(deadends);
  if (dead.has("0000")) return -1;
  if (target === "0000") return 0;
  const q = [["0000", 0]];
  const seen = new Set(["0000"]);
  while (q.length) {
    const [s, d] = q.shift();
    for (let i = 0; i < 4; i++) {
      for (const delta of [-1, 1]) {
        const nd = (Number(s[i]) + delta + 10) % 10;
        const nxt = s.slice(0, i) + nd + s.slice(i + 1);
        if (nxt === target) return d + 1;
        if (dead.has(nxt) || seen.has(nxt)) continue;
        seen.add(nxt);
        q.push([nxt, d + 1]);
      }
    }
  }
  return -1;
}
class Solution {
    public int openLock(String[] deadends, String target) {
        Set<String> dead = new HashSet<>(Arrays.asList(deadends));
        if (dead.contains("0000")) return -1;
        if (target.equals("0000")) return 0;
        Deque<String> q = new ArrayDeque<>();
        Set<String> seen = new HashSet<>();
        q.offer("0000"); seen.add("0000");
        int steps = 0;
        while (!q.isEmpty()) {
            steps++;
            int sz = q.size();
            for (int k = 0; k < sz; k++) {
                String s = q.poll();
                for (int i = 0; i < 4; i++) {
                    int c = s.charAt(i) - '0';
                    for (int delta : new int[]{-1, 1}) {
                        int nd = (c + delta + 10) % 10;
                        String nxt = s.substring(0, i) + nd + s.substring(i + 1);
                        if (nxt.equals(target)) return steps;
                        if (dead.contains(nxt) || seen.contains(nxt)) continue;
                        seen.add(nxt);
                        q.offer(nxt);
                    }
                }
            }
        }
        return -1;
    }
}
class Solution {
public:
    int openLock(vector<string>& deadends, string target) {
        unordered_set<string> dead(deadends.begin(), deadends.end());
        if (dead.count("0000")) return -1;
        if (target == "0000") return 0;
        queue<string> q;
        unordered_set<string> seen;
        q.push("0000"); seen.insert("0000");
        int steps = 0;
        while (!q.empty()) {
            steps++;
            int sz = q.size();
            for (int k = 0; k < sz; k++) {
                string s = q.front(); q.pop();
                for (int i = 0; i < 4; i++) {
                    int c = s[i] - '0';
                    for (int delta : {-1, 1}) {
                        int nd = (c + delta + 10) % 10;
                        string nxt = s; nxt[i] = '0' + nd;
                        if (nxt == target) return steps;
                        if (dead.count(nxt) || seen.count(nxt)) continue;
                        seen.insert(nxt);
                        q.push(nxt);
                    }
                }
            }
        }
        return -1;
    }
};
Time: O(10⁴ · 4) Space: O(10⁴)