[Leetcode] 打开转盘锁(BFS求最短路径)

news2025/7/13 17:00:44

题目链接:

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

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

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

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

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

示例 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
解释:无法旋转到目标数字且不被锁定。

每一位可以往上或往下拨1,一共有四位,每个转盘状态的下一个状态最多对应(=2*4)8种情况

说明:要除去deadends中的组合,以及拨到过的组合

这是一个多叉树的问题(层数和拨动次数对应),可以使用层序遍历,即BFS来找最短路径

BFS求最短路径

维护一个队列,一层层加子节点,如果子节点中有目标就返回

细节问题:

如果起点在deadends,开局就挂,返回-1

如果目标就是起点,开局躺赢,返回0

class Solution:
    def openLock(self, deadends: List[str], target: str) -> int:
        #用一个字典存相邻的数
        neighbor = {}
        for i in range(10):
            neighbor[str(i)] = [str((i+9)%10),str((i+11)%10)]

        if "0000" in deadends:
            return -1
        if target == "0000":
            return 0

        q = ["0000"]
        level = 0
        #搜索过的节点
        vis = {"0000"}

        while q:
            n = len(q)
            for i in range(n):
                tmp = q.pop(0)
                L = list(tmp)
                children = []
                for j in range(4):
                    num = L[j]
                    L[j] = neighbor[num][0]
                    children.append("".join(L))
                    L[j] = neighbor[num][1]
                    children.append("".join(L))
                    L[j] = num

                for child in children:
                    if child == target:
                        return level + 1
                    if child not in deadends and child not in vis:
                        vis.add(child)
                        q.append(child)

            level += 1
        return -1

双向BFS求最短路径

适用场景:知道target是什么、正序和反序搜索行为一样(这样会比较简单)

也可以同时从起点和终点搜索,随着层级越多BFS维护的队列会越来越长,搜索的越来越广。从两端同时搜索,可以减少多叉树下半部分的搜索广度。本题知道起点和终点,反向搜索也是上或下拨一。

细节问题:

维护两个队列q和q2,交替搜索下一层,可以每搜索完一层交换两个队列(q,q2 = q2,q),即形式上一直搜索的是q,每次查看搜索出来的子节点是否在q2中(在则相遇了,返回步数)

class Solution:
    def openLock(self, deadends: List[str], target: str) -> int:

        neighbor = {}
        for i in range(10):
            neighbor[str(i)] = [str((i+9)%10),str((i+11)%10)]

        if "0000" in deadends:
            return -1
        if target == "0000":
            return 0

        q = ["0000"]
        level = 0
        #搜索过的节点
        vis = {"0000",target}
        q2 = [target]
        
        while q and q2:
            n = len(q)
            for i in range(n):
                tmp = q.pop(0)
                L = list(tmp)
                children = []
                for j in range(4):
                    num = L[j]
                    L[j] = neighbor[num][0]
                    children.append("".join(L))
                    L[j] = neighbor[num][1]
                    children.append("".join(L))
                    L[j] = num

                for child in children:
                    if child in q2:
                        return level + 1
                    if child not in deadends and child not in vis:
                        vis.add(child)
                        q.append(child)

            level += 1
            q,q2 = q2,q
        return -1

执行时间会快一些

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/334869.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

你不会还不知道arrify的内部到底是怎么执行的吧?

作为一个前端工程师,经常会遇见转换成数组的需求,被转换的对象有可能是String、Set()、null、Map()、undefined、或者是数组本身。我们最经常的做法就是写一个arrify函数帮我去进行转换。久而久之因为经常会做不同的项目中遇到同样的需求所以我们通常会把…

WeNet - 初识

文章目录关于 WeNet快速上手识别训练环境准备训练关于 WeNet Production First and Production Ready End-to-End Speech Recognition Toolkit github: https://github.com/wenet-e2e/wenet官方中文说明:https://github.com/wenet-e2e/wenet/blob/main/README_CN.md…

分享宠物店微信小程序制作步骤_宠物店管理系统怎么做

大多数人对于动物医疗专业知识比较匮乏,再加上宠物医疗费用,日常用品都略高,宠物店/宠物医院的前景,再未来依旧可观。 相比于实体店,线上平台无疑有着更广阔的拓客渠道和销售前景,做宠物店/宠物医院小程序…

Java进阶(下篇)

Java进阶(下篇)Java进阶 P387一、IDEA使用与多线程1.概述①idea安装②IDEA常用设置③idea快捷键设置④模板的使用和设置2.程序进程、线程概念3.单核cpu与多核cpu任务执行_ 并行与并发4.多线程优点5.创建多线程方式一:继承Thread类6.线程常用方…

[oeasy]python0078_设置索引颜色_index_color_ansi_控制终端颜色

更多颜色 回忆上次内容 上次 了解了 高亮颜色 91-97 是 高亮 前景色101-107是 高亮 背景色 颜色种类 在原来基础上 增加了一些但也非常有限 还想要 更精细的颜色 有可能吗??🤔 更多颜色 继续深挖 关于 逃逸字符的文档 可以用 索引颜色 …

MyBatis源码概述及运行原理解析(篇一)

🐦MyBatis源码概述及运行原理解析 MyBatis的整体架构分为三层,分别是基础支持层、核心处理层和接口层 🖌 中文注释源码Git地址 🖽架构图 📂源码结构 📁parsing包 🗊parsing包对应基础支持层中…

Matlab论文插图绘制模板第76期—半对数刻度折线图(Semilogx和Semilogy)

在之前的文章中,分享了Matlab双对数刻度折线图的绘制模板: 进一步,再来分享一下半对数刻度折线图的绘制模板。 先来看一下成品效果: 特别提示:Matlab论文插图绘制模板系列,旨在降低大家使用Matlab进行科研…

为什么bitnami 安装的软件进入容器,用户名都是I have no name

文章目录背景原因user 参数的缺陷一### user 参数的缺陷二Docker 官方的解决方案背景 在bitnami 安装的软件进入容器用户名都显示I have no name,这是什么原因呢? 原因 在k8中容器默认好像是以uid1001启动的,可以修改该uid docker 启动的时…

leaflet 实现左卷帘效果 (代码示例045)

第045个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中实现左卷帘效果,这里主要引用了leaflet-side-by-side这个插件,直接调用的话,CSS方面有些问题,需要自行调整一下。 直接复制下面的 vue+leaflet源代码,操作2分钟即可运行实现效果 文章目录 示例效果配…

目标检测论文阅读:GaFPN算法笔记

标题:Construct Effective Geometry Aware Feature Pyramid Network for Multi-Scale Object Detection 会议:AAAI2022 论文地址:https://ojs.aaai.org/index.php/AAAI/article/view/19932 文章目录Abstract1. Introduction2. Related Work2.…

探索 Google 的 Bard AI 的强大功能

谷歌最近推出了名为“Bard AI”的新人工智能项目。 该项目旨在改善人工智能的语言和创造力,是谷歌旨在推进人工智能发展的更大“红色代码”计划的一部分。 该项目的主要目标是开发一种可以生成创意写作的语言模型。 什么是巴德人工智能? Bard AI 是一种…

Python 数据库开发实战 - Python与Redis交互篇- 缓存新闻数据至redis

实现新闻缓存功能 - “news_dao.py” - 从数据库提取明确的新闻数据保存至 redis - search_cache() 方法 只有在新闻被管理员审批通过的时候,新闻才可以缓存到 redis 里面。 管理员在 “审批新闻” 的时候是可以获得到 “被审批通过的新闻” 的 id,所以…

Allegro如何用Label Tune功能自动调整丝印到器件中心

Allegro如何用Label Tune功能自动调整丝印到器件中心 在做PCB设计的时候,调整丝印是比较费时的工作,如果需要把整板的丝印位号调整到器件的中心做装配图使用,Allegro的Label Tune功能支持快速把丝印位号居中到器件中心。 以下图为例,快速把所有丝印位号居中 调整前 调整后…

若依框架 --- 偶发的el-select无法选择的问题

👏作者简介:大家好,我是小童,Java开发工程师,CSDN博客博主,Java领域新星创作者 📕系列专栏:前端、Java、Java中间件大全、微信小程序、微信支付、若依框架、Spring全家桶 &#x1f4…

RBCD深度利用之“烂番茄”

1.RBCD简介 本篇文章是在基于资源的约束委派的基础上的一个利用,篇幅会比较短,但个人认为利用面还是挺广泛的。于是就写一下。 首先,需要了解的是RBCD的基础知识: 简单回顾一下: 基于资源的约束委派(RBCD) 只支持2…

微电网两阶段鲁棒优化经济调度方法[3]【升级优化版本】(Matlab代码实现)

💥💥💥💞💞💞欢迎来到本博客❤️❤️❤️💥💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑…

【论文速递】NAACL2022-DEGREE: 一种基于生成的数据高效事件抽取模型

【论文速递】NAACL2022-DEGREE: 一种基于生成的数据高效事件抽取模型 【论文原文】:DEGREE A Data-Efficient Generation-Based Event Extraction Mode 【作者信息】:I-Hung Hsu , Kuan-Hao Huang, Elizabeth Boschee &#xff…

【总结】1591- 从入门到精通:使用 TypeScript 开发超强的 CLI 工具

作为一名开发者,掌握 CLI 工具的开发能力是非常重要的。本文将指导你如何使用 TypeScript 和 CAC 库开发出功能强大的 CLI 工具。快速入门首先,需要先安装 Node.js 和 npm(Node Package Manager),然后在项目目录中创建…

【正点原子FPGA连载】第七章程序固化实验摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Vitis开发指南

第七章程序固化实验 在前面的几个实验中,我们都是通过JTAG接口将FPGA配置文件和应用程序下载到MPSOC器件中。接下来我们将尝试把程序存储在非易失性存储器中,在上电或者复位时让程序自动运行,这个过程需要启动引导程序(Boot Load…

【STM32笔记】HAL库UART串口配置及重定向(解决接收中断与scanf不能同时工作的问题)

【STM32笔记】HAL库UART串口配置及重定向&#xff08;解决接收中断与scanf不能同时工作的问题&#xff09; 首先 要使用printf和scanf 必不可少的就是 #include <stdio.h>这里需要做的就是配置单片机的UART 并且使其能够被printf和scanf调用 打开异步工作模式 并且选择…