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'.

这道题说有一种可滑动的四位数的锁,貌似行李箱上比较常见这种锁。给了我们一个目标值,还有一些死锁的情况,就是说如果到达这些死锁的位置,就不能再动了,相当于迷宫中的障碍物。然后问我们最少多少步可以从初始的0000位置滑动到给定的target位置。如果各位足够老辣的话,应该能发现其实本质就是个迷宫遍历的问题,只不过相邻位置不再是上下左右四个位置,而是四位数字每个都加一减一,总共有八个相邻的位置。遍历迷宫问题中求最短路径要用BFS来做,那么这道题也就是用BFS来解啦,和经典BFS遍历迷宫解法唯一不同的就是找下一个位置的地方,这里我们要遍历四位数字的每一位,然后分别加1减1,我们用j从-1遍历到1,遇到0跳过,也就是实现了加1减1的过程。然后我们要计算要更新位上的数字,为了处理9加1变0,和0减1变9的情况,我们统一给该位数字加上个10,然后再加或减1,最后再对10取余即可,注意字符和整型数之间通过加或减'0'来转换。我们用结果res来记录BFS遍历的层数,如果此时新生成的字符串等于target了,直接返回结果res,否则我们看如果该字符串不在死锁集合里,且之前没有遍历过,那么加入队列queue中,之后将该字符串加入visited集合中即可。注意这里在while循环中,由于要一层一层的往外扩展,一般的做法是会用一个变量len来记录当前的q.size(),博主为了简洁,使用了一个trick,就是从q.size()往0遍历,千万不能反回来,因为在计算的过程中q的大小会变化,如果让k < q.size() 为终止条件,绝b会出错,而我们初始化为q.size()就没事,参见代码如下:

解法一:

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

下面这种方法也是用的BFS遍历,不同之处在于生成新字符串的方法,这里我们采用拼接法来生成新字符串,而不是像上面那样使用置换字符串的方法。我们对于加一和减一分别进行拼接,注意处理9加1变0,和0减1变9的情况。然后剩下的部分就和经典的BFS遍历写法没有什么太大的区别了,参见代码如下:

解法二:

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

参考资料:

https://leetcode.com/problems/open-the-lock

https://leetcode.com/problems/open-the-lock/discuss/110230/BFS-solution-C++

https://leetcode.com/problems/open-the-lock/discuss/110237/Regular-java-BFS-solution-and-2-end-BFS-solution-with-improvement

LeetCode All in One 题目讲解汇总(持续更新中...)

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

  1. [LeetCode] 752. 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. java模拟开锁

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

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

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

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

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

  5. Coarse-Grained lock 粗粒度锁

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

  6. 4位开锁<dfs>

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

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

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

  8. hihocoder 1075 : 开锁魔法III

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

  9. JUC--Callable 以及Lock同步锁

    /** * 一.创建执行线程的方式三:实现Callable接口.相较于实现Runnable接口方式,方法可以有返回值,并且可以抛出异常 * 二.callable 需要FutureTask实现类的支持. ...

随机推荐

  1. [jdoj1090]矩阵_区间dp

    矩阵 jdoj-1910 题目大意:给你连续的n个矩阵的长和宽,保证每连续的两个相邻矩阵满足相乘的条件,不能改变题目中矩阵的位置,求将这些矩阵相乘为一个矩阵的最小乘法次数. 注释:1<=n< ...

  2. iptables.sh 初始化防火墙配置

    #!/bin/bash iptables -F iptables -X iptables -Z iptables -A INPUT -i lo -j ACCEPT iptables -A INPUT ...

  3. web 表单提交按钮的测试点

    web表单中的提交按钮的测试点: 在提交前需要理解清楚的点: 1.表单中哪些字段是必填项 2.表单中字段内容的限制:非空.重复.长度.特殊字符,空格.以及一些和业务相关的约束条件 测试点: 1.是否支 ...

  4. GitHub趋势:Vue.js大有超过TensorFlow之势!

    2月,Github上第二受欢迎的项目是Flutter.Flutter的第一个测试版本是作为2018年世界移动通信大会的一部分而开始的. Flutter是一款移动UI框架,旨在帮助开发人员在iOS和An ...

  5. Go实现海量日志收集系统(二)

    一篇文章主要是关于整体架构以及用到的软件的一些介绍,这一篇文章是对各个软件的使用介绍,当然这里主要是关于架构中我们agent的实现用到的内容 关于zookeeper+kafka 我们需要先把两者启动, ...

  6. C语言数据类型作业

    一.PTA实验作业 题目1:7-4 打印菱形图案 1. 本题PTA提交列表 2. 设计思路 1.定义m,n(用于计算空格数,输出"* "数),i,j,k(用于循环) 2.输入n,并 ...

  7. 团队作业7——Beta版本冲刺计划及安排

    上一个阶段的总结: 在Alpha阶段,我们小组已近完成了大部分的功能要求,小组的每一个成员都发挥了自己的用处.经过了这么久的磨合,小组的成员之间越来越默契,相信在接下来的合作中,我们的开发速度会越来越 ...

  8. python学习笔记-问题

    1.字典按照值进行排序输出 2.返回函数-闭包的使用

  9. mysql基础篇 - 其他基本操作

    基础篇 - 其他基本操作         其他基本操作 一.实验简介 本节实验中我们将学习并实践数据库的其他基本操作:索引.视图,导入和导出,备份和恢复等. 这些概念对于数据库管理员而言都非常重要,请 ...

  10. NetFPGA Demo ——reference_router_nf1_cml

    NetFPGA Demo --reference_router_nf1_cml 前言 本博文主要介绍了reference_router_nf1_cml该demo的一路运行,以及一路上艰难跑通遇到的坑. ...