You have a lock in front of you with 4 circular wheels. Each wheel has 10 slots: '0', '1', '2', '3', '4', '5', '6', '7', '8', '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 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.

Example 1:

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 dead end "0102". 

Example 2:

Input: deadends = ["8888"], target = "0009"
Output: 1
Explanation:
We can turn the last wheel in reverse to move from "0000" -> "0009".

Example 3:

Input: deadends = ["8887","8889","8878","8898","8788","8988","7888","9888"], target = "8888"
Output: -1
Explanation:
We can't reach the target without getting stuck.

Example 4:

Input: deadends = ["0000"], target = "8888"
Output: -1

Note:

  1. The length of deadends will be in the range [1, 500].
  2. target will not be in the list deadends.
  3. Every string in deadends and the string target will be a string of 4 digits from the 10,000 possibilities '0000' to '9999'.

Hint:

We can think of this problem as a shortest path problem on a graph: there are `10000` nodes (strings `'0000'` to `'9999'`), and there is an edge between two nodes if they differ in one digit, that digit differs by 1 (wrapping around, so `'0'` and `'9'` differ by 1), and if *both* nodes are not in `deadends`.

有一个可转动的四位数的密码锁,给一个目标值,还有一些锁死的情况,出现死锁的位置,就不能再动了,相当于迷宫中的障碍物。问最少多少步可以从初始的0000位置转动到给定的target位置。

可以把问题想成图的最短路径问题,有10000个节点(字符串‘0000'到'9999'),如果两个节点之间相差1并且不在锁死节点中,则它们之间有一个边。类似于迷宫遍历的问题,只不过相邻位置不再是上下左右四个位置,而是四位数字每个都加一减一,总共有八个相邻的位置。

解法:BFS

Java:

public static int openLock(String[] deadends, String target) {
Queue<String> q = new LinkedList<>();
Set<String> deads = new HashSet<>(Arrays.asList(deadends));
Set<String> visited = new HashSet<>(); int depth = 0;
String marker = "*";
q.addAll(Arrays.asList("0000", "*"));
while(!q.isEmpty()) {
String node = q.poll();
if(node.equals(target))
return depth;
if(visited.contains(node) || deads.contains(node))
continue;
if(node.equals(marker) && q.isEmpty())
return -1;
if(node.equals(marker)) {
q.add(marker);
depth += 1;
} else {
visited.add(node);
q.addAll(getSuccessors(node));
}
}
return depth;
} private static List<String> getSuccessors(String str) {
List<String> res = new LinkedList<>();
for (int i = 0; i < str.length(); i++) {
res.add(str.substring(0, i) + (str.charAt(i) == '0' ? 9 : str.charAt(i) - '0' - 1) + str.substring(i+1));
res.add(str.substring(0, i) + (str.charAt(i) == '9' ? 0 : str.charAt(i) - '0' + 1) + str.substring(i+1));
}
return res;
}  

Python:

Shortest path finding, when the weights are constant, as in this case = 1, BFS is the best way to go.

Best way to avoid TLE is by using deque and popleft() .
[Using list() and pop(0) is a linear operation in Python, resulting in TLE]

class Solution(object):
def openLock(self, deadends, target):
"""
:type deadends: List[str]
:type target: str
:rtype: int
"""
marker, depth = 'x', 0
visited, q, deadends = set(), deque(['0000', marker]), set(deadends) while q:
node = q.popleft()
if node == target:
return depth
if node in visited or node in deadends:
continue
if node == marker and not q:
return -1
if node == marker:
q.append(marker)
depth += 1
else:
visited.add(node)
q.extend(self.successors(node))
return -1 def successors(self, src):
res = []
for i, ch in enumerate(src):
num = int(ch)
res.append(src[:i] + str((num - 1) % 10) + src[i+1:])
res.append(src[:i] + str((num + 1) % 10) + src[i+1:])
return res  

Python:

# Time:  O(k * n^k + d), n is the number of alphabets,
# k is the length of target,
# d is the size of deadends
# Space: O(k * n^k + d)
class Solution(object):
def openLock(self, deadends, target):
"""
:type deadends: List[str]
:type target: str
:rtype: int
"""
dead = set(deadends)
q = ["0000"]
lookup = {"0000"}
depth = 0
while q:
next_q = []
for node in q:
if node == target: return depth
if node in dead: continue
for i in xrange(4):
n = int(node[i])
for d in (-1, 1):
nn = (n+d) % 10
neighbor = node[:i] + str(nn) + node[i+1:]
if neighbor not in lookup:
lookup.add(neighbor)
next_q.append(neighbor)
q, next_q = next_q, []
depth += 1
return -1  

C++:

class Solution {
public:
int openLock(vector<string>& deadends, string target) {
unordered_set<string> deadlock(deadends.begin(), deadends.end());
if (deadlock.count("0000")) return -1;
int res = 0;
unordered_set<string> visited{{"0000"}};
queue<string> q{{"0000"}};
while (!q.empty()) {
++res;
for (int k = q.size(); k > 0; --k) {
auto t = q.front(); q.pop();
for (int i = 0; i < t.size(); ++i) {
for (int j = -1; j <= 1; ++j) {
if (j == 0) continue;
string str = t;
str[i] = ((t[i] - '0') + 10 + j) % 10 + '0';
if (str == target) return res;
if (!visited.count(str) && !deadlock.count(str)) q.push(str);
visited.insert(str);
}
}
}
}
return -1;
}
};

C++:  

class Solution {
public:
int openLock(vector<string>& deadends, string target) {
unordered_set<string> deadlock(deadends.begin(), deadends.end());
if (deadlock.count("0000")) return -1;
int res = 0;
unordered_set<string> visited{{"0000"}};
queue<string> q{{"0000"}};
while (!q.empty()) {
++res;
for (int k = q.size(); k > 0; --k) {
auto t = q.front(); q.pop();
for (int i = 0; i < t.size(); ++i) {
char c = t[i];
string str1 = t.substr(0, i) + to_string(c == '9' ? 0 : c - '0' + 1) + t.substr(i + 1);
string str2 = t.substr(0, i) + to_string(c == '0' ? 9 : c - '0' - 1) + t.substr(i + 1);
if (str1 == target || str2 == target) return res;
if (!visited.count(str1) && !deadlock.count(str1)) q.push(str1);
if (!visited.count(str2) && !deadlock.count(str2)) q.push(str2);
visited.insert(str1);
visited.insert(str2);
}
}
}
return -1;
}
};

  

All LeetCode Questions List 题目汇总

[LeetCode] 752. Open the Lock 开锁的更多相关文章

  1. [LeetCode] Open the Lock 开锁

    You have a lock in front of you with 4 circular wheels. Each wheel has 10 slots: '0', '1', '2', '3', ...

  2. LeetCode 752. Open the Lock

    原题链接在这里:https://leetcode.com/problems/open-the-lock/ 题目: You have a lock in front of you with 4 circ ...

  3. java模拟开锁

    java模拟开锁 service qq:928900200 Introduction to Computer Science II: CSCI142Fall 2014Lab #1Instructor: ...

  4. Java并发编程之Lock(同步锁、死锁)

    这篇文章是接着我上一篇文章来的. 上一篇文章 同步锁 为什么需要同步锁? 首先,我们来看看这张图. 这是一个程序,多个对象进行抢票. package MovieDemo; public class T ...

  5. [C#基础]说说lock到底锁谁?

    写在前面 最近一个月一直在弄文件传输组件,其中用到多线程的技术,但有的地方确实需要只能有一个线程来操作,如何才能保证只有一个线程呢?首先想到的就是锁的概念,最近在我们项目组中听的最多的也是锁谁,如何锁 ...

  6. Coarse-Grained lock 粗粒度锁

    用一个锁Lock一组相关的对象 有时,需要按组来修改多个对象. 这样,在需要锁住其中一个的时候,必须连带地将其他的对象都上锁. 为每一个对象都加上一个锁是很繁琐的. 粗粒度锁是覆盖多个对象的单个锁. ...

  7. 4位开锁<dfs>

    题意: 有一个四位密码的锁,每一位是1~9的密码,1跟9相连.并且相邻的连个密码位可以交换.每改变一位耗时1s,给出锁的当前状态和密码,求最少解锁时间. 思路: 用bfs枚举出所有相邻交换的情况,并记 ...

  8. Java 线程锁机制 -Synchronized Lock 互斥锁 读写锁

    (1)synchronized 是互斥锁: (2)ReentrantLock 顾名思义 :可重入锁 (3)ReadWriteLock :读写锁 读写锁特点: a)多个读者可以同时进行读b)写者必须互斥 ...

  9. hihocoder 1075 : 开锁魔法III

    描述 一日,崔克茜来到小马镇表演魔法. 其中有一个节目是开锁咒:舞台上有 n 个盒子,每个盒子中有一把钥匙,对于每个盒子而言有且仅有一把钥匙能打开它.初始时,崔克茜将会随机地选择 k 个盒子用魔法将它 ...

随机推荐

  1. Good Numbers(HDU5447+唯一分解)

    题目链接 传送门 题面 题意 首先定义对于\(k\)的好数\(u\):如果\(u\leq k\)且\(u\)的所有质因子与\(k\)的质因子一样则称\(u\)对于\(k\)是一个好数. 现给你两个数\ ...

  2. 微信小程序之执行环境

    明白了小程序中的 JavaScript 同浏览器以及NodeJS有所不同后,开发者还需要注意到另外一个问题,不同的平台的小程序的脚本执行环境也是有所区别的. 小程序目前可以运行在三大平台: iOS平台 ...

  3. 使用aliyun的oss服务器上传照片

    1.控制台操作 首先介绍一下阿里云OSS对象存储的一些基本概念. 1.1 进入对象存储界面 登录阿里云账号,进入对象存储界面,如图所示. 进入后如图所示. 1.2 OSS基本概念 这里不过多介绍如何在 ...

  4. 机房断电,导致xfs文件系统损坏

    记一次机房断电,导致xfs文件系统损坏处理方法 挂载时报以下错误: mount: mount /dev/sdb on /dev/sdb failed: Structure needs cleaning ...

  5. C++对象内存模型1(堆栈模型)(转)

    对象内存模型 一. 栈(Stack) VS. 堆(heap) 栈 由系统自动管理,以执行函数为单位 空间大小编译时确定(参数+局部变量) 函数执行时,系统自动分配一个stack 函数执行结束时,系统立 ...

  6. django-缓存django-redis

    https://django-redis-chs.readthedocs.io/zh_CN/latest/ 安装 django-redis 最简单的方法就是用 pip : pip install dj ...

  7. Vue --- 指令练习

    scores = [ { name: 'Bob', math: 97, chinese: 89, english: 67 }, { name: 'Tom', math: 67, chinese: 52 ...

  8. mysql udf提权

    参考文章:https://blog.csdn.net/q1352483315/article/details/98483668

  9. (3) esp8266 官方库文件,没有求逆函数

    下载库文件 #include <MatrixMath.h> #define N (2) mtx_type A[N][N]; mtx_type B[N][N]; mtx_type C[N][ ...

  10. java.lang.IllegalAccessException: void #####.MyBroadcastReceiver.() is not accessible from jav

    java.lang.IllegalAccessException: void #####.MyBroadcastReceiver.<init>() is not accessible fr ...