You have a lock in front of you with 4 circular wheels. Each wheel has 10 slots, labeled ‘0’ to ‘9’. The wheels can rotate freely, and 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, meaning if the lock displays any of these codes, the wheels of the lock get stuck, and you cannot turn them anymore.
Given a target representing the code that you want to unlock, return the minimum total number of turns required to open the lock, or -1 if it is impossible.
Input: deadends = ["0201","0101","0102","1212","2002"], target = "0202"
Output: 6
Explanation:
A sequence of valid moves would be "0000" -> "1000" -> "1100" -> "1200" -> "1201" -> "1202" -> "0202".
Note that a sequence like "0000" -> "0001" -> "0002" -> "0102" -> "0202" would be invalid, because the wheels of the lock become stuck after the display becomes the deadend "0102".
#include <iostream>
#include <vector>
#include <unordered_set>
#include <queue>
using namespace std;
int openLock(vector<string>& deadends, string target) {
unordered_set<string> dead(deadends.begin(), deadends.end());
unordered_set<string> visited;
queue<string> q;
int steps = 0;
q.push("0000");
visited.insert("0000");
while (!q.empty()) {
int qsize = q.size();
for (int i = 0; i < qsize; ++i) {
string curr = q.front();
q.pop();
// If the current state is in the deadends, skip it
if (dead.find(curr) != dead.end()) continue;
// If the target is found, return steps
if (curr == target) return steps;
// Explore the next states
for (int j = 0; j < 4; ++j) {
string up = curr;
string down = curr;
// Rotate the j-th wheel up
up[j] = (curr[j] - '0' + 1) % 10 + '0';
if (visited.find(up) == visited.end()) {
q.push(up);
visited.insert(up);
}
// Rotate the j-th wheel down
down[j] = (curr[j] - '0' + 9) % 10 + '0';
if (visited.find(down) == visited.end()) {
q.push(down);
visited.insert(down);
}
}
}
++steps;
}
// If the target was never reached
return -1;
}
int main() {
vector<string> deadends = {"0201","0101","0102","1212","2002"};
string target = "0202";
cout << openLock(deadends, target) << endl; // Output: 6
return 0;
}
This approach ensures the shortest path is found from the start state to the target while avoiding deadends efficiently through BFS.
Got blindsided by a question you didn’t expect?
Spend too much time studying?
Or simply don’t have the time to go over all 3000 questions?