[LeetCode] 0752. Open the Lock 打开转盘锁
题目
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.
你有一个带有四个圆形拨轮的转盘锁。每个拨轮都有10个数字: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 。每个拨轮可以自由旋转:例如把 '9' 变为 '0','0' 变为 '9' 。每次旋转都只能旋转一个拨轮的一位数字。
锁的初始数字为 '0000' ,一个代表四个拨轮的数字的字符串。
列表 deadends 包含了一组死亡数字,一旦拨轮的数字和列表里的任何一个元素相同,这个锁将会被永久锁定,无法再被旋转。
字符串 target 代表可以解锁的数字,你需要给出最小的旋转次数,如果无论如何不能解锁,返回 -1。
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:
The length of deadends will be in the range [1, 500].
target will not be in the list deadends.
Every string in deadends and the string target will be a string of 4 digits from the 10,000 possibilities '0000' to '9999'.
解法一
思路:就是一道简单的BFS搜索题,要注意的点就是每次搜索时,要先遍历队列中的所有元素,全部处理完了再做第二轮搜索。还有就是在遍历队列并修改时,要先把size存下来,否则会得到错误的结果。
不足:不知道为什么运行速度和内存使用都这么大,一方面可能是计算移动时直接用的字符操作,效果没有用int来的快,一方面是visted用的unordered_set<string>,效率和内存肯定是没有bool visited[10000] + memset(visited, 0, sizeof(visited))来的好。
重新刷leetcode的第二天,先这样实现了练练手,之后再做性能改进吧。
class Solution {
public:
int openLock(vector<string>& deadends, string target) {
unordered_set<string> deadset(deadends.begin(), deadends.end());
if (deadset.count("0000")) {
return -1;
}
queue<string> q;
unordered_set<string> visited;
q.push("0000");
visited.insert("0000");
int result = 0;
// 开始BFS搜索
while (!q.empty()) {
result++;
auto size = q.size();
for (int i = 0; i < size; i++) {
string seq = q.front();
q.pop();
// 获取所有有效移动
auto moves = getValidMoves(seq);
for (auto& move : moves) {
if (move == target) {
return result;
}
// 如果该移动不是deadend且没访问过,则入队
if (!deadset.count(move) && !visited.count(move)) {
q.push(move);
visited.insert(move);
}
// 如果是deadend则不做处理,相当于绕过deadend
}
}
}
// 没有找到目标序列,返回-1
return -1;
}
vector<string> getValidMoves(const string& sequence) {
vector<string> moves;
for (int i = 0; i < 4; i++) {
string temp = sequence;
// +1
temp[i] = temp[i] == '9' ? '0' : temp[i] + 1;
moves.push_back(temp);
// -1
temp = sequence;
temp[i] = temp[i] == '0' ? '9' : temp[i] - 1;
moves.push_back(temp);
}
return moves;
}
};
运行结果:
Runtime: 324 ms, faster than 27.97% of C++ online submissions for Open the Lock.
Memory Usage: 106.9 MB, less than 17.31% of C++ online submissions for Open the Lock.
解法二
可以说的上非常神奇了,首先仔细观察题目,可以发现以下几点:
- 目标不可达的条件是,deadends里必须有只和target差一步的序列(例如deadends = "8888", target = "8889"),也就是说,可以直接从deadends中看出target是否可达;
- 直接计算所有可达结果(target的前一步)的所需步长,并计算最小步长即可,根本不需要用到BFS;
这个算法真是可遇不可求呀~
class Solution {
public:
int openLock(vector<string>& deadends, string target) {
unordered_set<string> deadset(deadends.begin(), deadends.end());
if (deadset.count("0000") || deadset.count(target)) {
return -1;
}
vector<string> movesToTarget;
auto moves = getValidMoves(target);
for (auto& move : moves) {
if (!deadset.count(move)) {
movesToTarget.push_back(move);
}
}
// 可以直接从deadends中看出target可不可达
if (movesToTarget.empty()) {
return -1;
}
// 最大步长是40步(每位转动10次)
int min_stride = 40;
// 计算到达每个可达结果的步长,取最小
for (auto& move : movesToTarget) {
int cur_stride = 0;
for (int i = 0; i < 4; ++i) {
int turns = move[i] - '0';
// 可以倒着转,所以转动次数不会大过5
if (turns > 5) {
turns = 10 - turns;
}
cur_stride += turns;
}
if (cur_stride < min_stride) {
min_stride = cur_stride;
}
}
// 最后加上到达target的那一步
return min_stride + 1;
}
vector<string> getValidMoves(const string& sequence) {
vector<string> moves;
for (int i = 0; i < 4; i++) {
string temp = sequence;
// +1
temp[i] = temp[i] == '9' ? '0' : temp[i] + 1;
moves.push_back(temp);
// -1
temp = sequence;
temp[i] = temp[i] == '0' ? '9' : temp[i] - 1;
moves.push_back(temp);
}
return moves;
}
};
运行结果:
Runtime: 8 ms, faster than 100.00% of C++ online submissions for Open the Lock.
Memory Usage: 10.3 MB, less than 98.08% of C++ online submissions for Open the Lock.
[LeetCode] 0752. Open the Lock 打开转盘锁的更多相关文章
- Leetcode之广度优先搜索(BFS)专题-752. 打开转盘锁(Open the Lock)
Leetcode之广度优先搜索(BFS)专题-752. 打开转盘锁(Open the Lock) BFS入门详解:Leetcode之广度优先搜索(BFS)专题-429. N叉树的层序遍历(N-ary ...
- Java实现 LeetCode 752 打开转盘锁(暴力)
752. 打开转盘锁 你有一个带有四个圆形拨轮的转盘锁.每个拨轮都有10个数字: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' .每个拨轮可以自由旋 ...
- LeetCode 752:打开转盘锁 Open the Lock
题目: 你有一个带有四个圆形拨轮的转盘锁.每个拨轮都有10个数字: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' .每个拨轮可以自由旋转:例如把 ' ...
- [Swift]LeetCode752. 打开转盘锁 | Open the Lock
You have a lock in front of you with 4 circular wheels. Each wheel has 10 slots: '0', '1', '2', '3', ...
- leetcode 752. 打开转盘锁
地址 https://leetcode-cn.com/problems/open-the-lock/ 你有一个带有四个圆形拨轮的转盘锁.每个拨轮都有10个数字: '0', '1', '2', '3', ...
- leetcode752. 打开转盘锁
我们可以将 0000 到 9999 这 10000 状态看成图上的 10000 个节点,两个节点之间存在一条边,当且仅当这两个节点对应的状态只有 1 位不同,且不同的那位相差 1(包括 0 和 9 也 ...
- java里的锁总结(synchronized隐式锁、Lock显式锁、volatile、CAS)
一.介绍 首先, java 的锁分为两类: 第一类是 synchronized 同步关键字,这个关键字属于隐式的锁,是 jvm 层面实现,使用的时候看不见: 第二类是在 jdk5 后增加的 Lock ...
- [转载] java并发编程:Lock(线程锁)
作者:海子 原文链接: http://www.cnblogs.com/dolphin0520/p/3923167.html 出处:http://www.cnblogs.com/dolphin0520/ ...
- python之GIL官方文档 global interpreter lock 全局解释器锁
0.目录 2. 术语 global interpreter lock 全局解释器锁3. C-API 还有更多没有仔细看4. 定期切换线程5. wiki.python6. python.doc FAQ ...
随机推荐
- 用Vue2.0实现简单的分页及跳转
用Vue2.0实现简单的分页及跳转 2018年07月26日 20:29:51 Freya_yyy 阅读数 3369 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog ...
- 多个进程间通信之Queue
多个进程间通信之Queue 实现数据传递 #!coding:utf-8 from multiprocessing import Process, Queue import os,time,random ...
- 使用二进制的方式部署 K8S-1.16 高可用集群
一.项目介绍 项目致力于让有意向使用原生kubernetes集群的企业或个人,可以方便的.系统的使用二进制的方式手工搭建kubernetes高可用集群.并且让相关的人员可以更好的理解kubernete ...
- UE4 ios环境搭建备忘
1.windows.mac安装证书 2.安装xcode .app -- 路径可以拖入 sudo gem install xcodeproj 3.错误处理 Setting up Mono Running ...
- [转]综述论文翻译:A Review on Deep Learning Techniques Applied to Semantic Segmentation
近期主要在学习语义分割相关方法,计划将arXiv上的这篇综述好好翻译下,目前已完成了一部分,但仅仅是尊重原文的直译,后续将继续完成剩余的部分,并对文中提及的多个方法给出自己的理解. _论文地址:htt ...
- C++ 读取 MATLAB 的 .m 文件,并发送到 MATLAB 运行
本代码是由「Microsoft Visual Studio 2015 Enterprise」编写. 想要了解更多 C++ 与 MATLAB 混合编程的知识,可以参考我的另一篇博客:C++ 与 MATL ...
- python with方法
在实际的编码过程中,有时有一些任务,需要事先做一些设置,事后做一些清理,这时就需要python with出场了,with能够对这样的需求进行一个比较优雅的处理,最常用的例子就是对访问文件的处理. 一般 ...
- TensorFlow学习笔记(1)—— 基本概念与框架
入门框架时的常见问题 学习框架的原因? 方便.易用 学习框架的哪些知识点? 掌握一个项目的基本流程,就知道需要学习哪些知识点了 迅速学习框架的方法 根据项目每块流程的需要针对性的学 可以看官方的入门教 ...
- iview 表格随着更改刷新
使用location.reload() 或者是 路由的 this.$router.go(0) 进行刷新的时候,是会出现一阵的空白区域的,因为是整个页面的刷新 ,所以比较缓慢,因此使用了provide/ ...
- java8之lambda表达式(默认方法)
[推荐]2019 Java 开发者跳槽指南.pdf(吐血整理)>>> 许多开发语言都将函数表达式集成到了其集合库中.这样比循环方式所需的代码更少,并且更加容易理解.以下面的循环为例: ...