LeetCode 752:打开转盘锁 Open the Lock

简介: 题目:你有一个带有四个圆形拨轮的转盘锁。每个拨轮都有10个数字: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 。每个拨轮可以自由旋转:例如把 '9' 变为 '0','0'变为 '9' 。

题目:

你有一个带有四个圆形拨轮的转盘锁。每个拨轮都有10个数字: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 。每个拨轮可以自由旋转:例如把 '9' 变为 '0''0'变为 '9' 。每次旋转都只能旋转一个拨轮的一位数字。

锁的初始数字为 '0000' ,一个代表四个拨轮的数字的字符串。

列表 deadends 包含了一组死亡数字,一旦拨轮的数字和列表里的任何一个元素相同,这个锁将会被永久锁定,无法再被旋转。

字符串 target 代表可以解锁的数字,你需要给出最小的旋转次数,如果无论如何不能解锁,返回 -1。

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.

示例 1:

输入:deadends = ["0201","0101","0102","1212","2002"], target = "0202"
输出:6
解释:
可能的移动序列为 "0000" -> "1000" -> "1100" -> "1200" -> "1201" -> "1202" -> "0202"。
注意 "0000" -> "0001" -> "0002" -> "0102" -> "0202" 这样的序列是不能解锁的,
因为当拨动到 "0102" 时这个锁就会被锁定。

示例 2:

输入: deadends = ["8888"], target = "0009"
输出:1
解释:
把最后一位反向旋转一次即可 "0000" -> "0009"。

示例 3:

输入: deadends = ["8887","8889","8878","8898","8788","8988","7888","9888"], target = "8888"
输出:-1
解释:
无法旋转到目标数字且不被锁定。

示例 4:

输入: deadends = ["0000"], target = "8888"
输出:-1

提示:

  1. 死亡列表 deadends 的长度范围为 [1, 500]
  2. 目标数字 target 不会在 deadends 之中。
  3. 每个 deadendstarget 中的字符串的数字会在 10,000 个可能的情况 '0000''9999' 中产生。

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

解题思路:

题目要求给出最小的旋转次数,应该就是用 BFS(广度优先搜索)解题了。初始字符串为 "0000" 那么第二步就是 "1000" "9000" "0100" "0900" "0010" "0090" "0001" "0009" 共八个字符串,也就是说每一步的字符串拨动密码扩展到下一步时可以得到八个新字符串。把它想象成图的形式:很明显相当于每个节点后有八个节点,用 BFS 每次走一个节点,直到达到目标节点,即是最短路径。

另外需要注意:每次到要判断节点是否为给出的死亡数字,并且把已遍历的节点也加入死亡数字以防止重复。这样只能将原数组形式的死亡数字转为哈希表以减少查找操作的复杂度。用队列暂存下一步需要遍历的节点。Java、python无法直接修改字符串里的字符.Java可先转换成 char 型数组,python可借助切片组装新字符串。

Java:

class Solution {
    public int openLock(String[] deadends, String target) {
        HashSet<String> dead_set = new HashSet<>(Arrays.asList(deadends));//死亡数字转为哈希表
        if (dead_set.contains("0000")) return -1;//死亡数字如果含有初始节点,返回-1
        Queue<String> queue = new LinkedList<>();//队列
        queue.add("0000");//加入初始节点
        int count = 0;//记录步数
        while (!queue.isEmpty()) {//节点未访问完,队列内的节点不为空
            int size = queue.size();//每一步节点数
            while (size-- > 0) {
                String tmp = queue.remove();//弹出头节点
                if (target.equals(tmp)) return count;//如果与目标数相同,直接返回步数
                char[] c = tmp.toCharArray();//转为数组
                for (int j = 0; j < 4; j++) {//每次修改四位数字的一位
                    int i = c[j] - '0';//转为int型
                    c[j] = (char) ('0' + (i + 9) % 10);//数字-1。余数运算可防止节点为0、9时出现-1、10的情况
                    String s = new String(c);//得到新字符串
                    if (!dead_set.contains(s)) {//字符串不在死亡数字中时
                        queue.add(s);//添加到队列作为下一步需要遍历的节点
                        dead_set.add(s);//下一步必访问该节点,所以可先加入到死亡数字
                    }
                    c[j] = (char) ('0' + (i + 11) % 10);//数字+1
                    s = new String(c);
                    if (!dead_set.contains(s)) {
                        queue.add(s);
                        dead_set.add(s);
                    }
                    c[j] = (char) ('0' + i);
                }
            }
            count++;
        }
        return -1;
    }
}

Python:

class Solution:
    def openLock(self, deadends: List[str], target: str) -> int:
        #转成哈希表
        dead_set = set(deadends)
        if '0000' in dead_set: return -1
        que = collections.deque(['0000'])
        count = 0
        while que:
            for x in range(len(que)):
                #从左取出头节点
                tmp = que.popleft()
                if tmp == target: return count
                for i in range(4):
                    #分别存修改字符的左半部分字符串,待修改字符(转成int),右半部分字符
                    left, mid, right = tmp[:i], int(tmp[i]), tmp[i + 1:]
                    #j数字加一、减一拨动操作
                    for x in [-1, 1]:
                        s = left + str((mid + x) % 10) + right#切片拼接字符
                        if not s in dead_set:
                            dead_set.add(s)
                            que.append(s)
            count += 1
        return -1

关注微.信.公.众号:爱写Bug,一起学习吖

目录
相关文章
|
测试技术 C++
【LeetCode752】打开转盘锁(BFS)
【LeetCode752】打开转盘锁(BFS) 每个节点有8个孩子节点,如题目给的第二个测试用例,start=0000时,4个位置分别可以向上转or向下转,得到1000、9000、0100、0900等8种情况。即这是一棵八叉树。即求解从start数字到target的最短路径。为了找到最小旋转次次数,利用BFS逐层查找,遇到target则返回树高度(层数)。
137 0
【LeetCode752】打开转盘锁(BFS)
|
3月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
4月前
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
59 6
|
4月前
|
Python
【Leetcode刷题Python】剑指 Offer 26. 树的子结构
这篇文章提供了解决LeetCode上"剑指Offer 26. 树的子结构"问题的Python代码实现和解析,判断一棵树B是否是另一棵树A的子结构。
53 4
|
4月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
121 2
|
1月前
|
机器学习/深度学习 人工智能 自然语言处理
280页PDF,全方位评估OpenAI o1,Leetcode刷题准确率竟这么高
【10月更文挑战第24天】近年来,OpenAI的o1模型在大型语言模型(LLMs)中脱颖而出,展现出卓越的推理能力和知识整合能力。基于Transformer架构,o1模型采用了链式思维和强化学习等先进技术,显著提升了其在编程竞赛、医学影像报告生成、数学问题解决、自然语言推理和芯片设计等领域的表现。本文将全面评估o1模型的性能及其对AI研究和应用的潜在影响。
36 1
|
3月前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
|
4月前
|
索引 Python
【Leetcode刷题Python】从列表list中创建一颗二叉树
本文介绍了如何使用Python递归函数从列表中创建二叉树,其中每个节点的左右子节点索引分别是当前节点索引的2倍加1和2倍加2。
67 7
|
4月前
|
Python
【Leetcode刷题Python】剑指 Offer 22. 链表中倒数第k个节点
Leetcode题目"剑指 Offer 22. 链表中倒数第k个节点"的Python解决方案,使用双指针法找到并返回链表中倒数第k个节点。
54 5
|
4月前
|
Python
【Leetcode刷题Python】剑指 Offer 30. 包含min函数的栈
本文提供了实现一个包含min函数的栈的Python代码,确保min、push和pop操作的时间复杂度为O(1)。
30 4