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. 动态域名作为dga的做法

    https://wenku.baidu.com/view/54b1df373968011ca3009183.html dga算法 import time from ctypes import c_in ...

  2. Python练习——约瑟夫环问题、用类方法描述一个数字时钟

    一.约瑟夫环问题 有15个基督徒和15个非基督徒在海上遇险,为了能让一部分人活下来不得不将其中15个人扔到海里面去,有个人想了个办法就是大家围成一个圈,由某个人开始从1报数,报到9的人就扔到海里面,他 ...

  3. MySQL——查询优化|47s到0.1s|我做了什么

    前言 这个代码是之前的同事写的,现在我接管了,但是今天早上我打开这个模块的时候发现数据加载异常的缓慢,等了将近一分钟左右数据才显示到页面. 这特么的绝对不正常啊,数据量压根没那么多呀,这特喵的什么情况 ...

  4. 使用mybatis框架实现带条件查询-多条件(传入实体类)

    在实际的项目开发中,使用mybatis框架查询的时候,不可能是只有一个条件的,大部分情况下是有多个条件的,那么多个条件应该怎样传入参数: 思考:  需求:根据用户姓名(模糊查询),和用户角色对用户表进 ...

  5. 浏览器报400-Bad Request异常

    今天在使用ie浏览器在测试程序的时候,报这个错误,后台日志打印出来显示的是:连接一个远程主机失败 解决Invalid character found in the request target. Th ...

  6. 11、 Hadoop 2.x各个服务组件如何配置在那台服务器运行并测试

    HDFS模块 NameNode:是由哪个文件中的哪个配置属性指定的呢? core-site.xml文件中: <property> <name>fs.defaultFS</ ...

  7. 10.31-11.1Test(未完)

    10.31-11.1Test 题目 描述 做法 \(BSOJ5177\) 求在\(n\)个数里选\(K\)个的所有方案的异或和之和 按位讨论,组合数算 \(BSOJ5178\) 化简\(\displa ...

  8. 1-开发共享版APP(接入指南)-APP说明

    该APP的功能,类似于网上售卖的Wi-Fi/GPRS远程控制器 设备页面                                     用户页面                       ...

  9. java如何判断溢出

    public int reverse2(int x) { double ans=0; int flag=1; if(x<0){ flag=-1; } x=x*flag; while(x>0 ...

  10. 【JZOJ6226】【20190618】纳什均衡

    题目 一颗二叉树,每个点儿子个数为0 或 2 ,对每个叶子有一个权值\((c(u),d(u))\) 从根结点开始走,Alice 可以选择奇数层的走法,Bob 可以选择偶数层的走法,分别获得最后走到叶子 ...