Leetcode 864. 获取所有钥匙的最短路径

news/2024/10/10 14:18:24/文章来源:https://www.cnblogs.com/geek0070/p/18456251

1.题目基本信息

1.1.题目描述

给定一个二维网格 grid ,其中:

  • ‘.’ 代表一个空房间
  • ‘#’ 代表一堵墙
  • ‘@’ 是起点
  • 小写字母代表钥匙
  • 大写字母代表锁

我们从起点开始出发,一次移动是指向四个基本方向之一行走一个单位空间。我们不能在网格外面行走,也无法穿过一堵墙。如果途经一个钥匙,我们就把它捡起来。除非我们手里有对应的钥匙,否则无法通过锁。

假设 k 为 钥匙/锁 的个数,且满足 1 <= k <= 6,字母表中的前 k 个字母在网格中都有自己对应的一个小写和一个大写字母。换言之,每个锁有唯一对应的钥匙,每个钥匙也有唯一对应的锁。另外,代表钥匙和锁的字母互为大小写并按字母顺序排列。

返回获取所有钥匙所需要的移动的最少次数。如果无法获取所有钥匙,返回 -1 。

1.2.题目地址

https://leetcode.cn/problems/shortest-path-to-get-all-keys/description/

2.解题方法

2.1.解题思路

BFS+字符串标记钥匙状态/二进制标记钥匙状态

2.2.解题步骤

第一步,将各个钥匙字符离散化为0,1,2…的数字

第二步,使用广度优先搜索遍历每个节点。BFS的使用队列存储遍历项,遍历的项为结构为(x坐标,y坐标,当前步数,当前已获取的钥匙的状态字符串),同时使用visited集合存储已经访问的不可重复状态,访问项结构为(x坐标,y坐标,当前已获取的钥匙的状态字符串);现将钥匙的状态字符串记为keys,keys[i]=”1″代表已经获取到了离散值为i的钥匙,等于”0″则代表没有获取到。这里BFS的判断是否将下一个点(nx,ny)加入到队列的逻辑相对于普通的BFS更复杂,因为当碰到钥匙时,其前面的路径上的部分点是可以重复访问的,所以的前面的visited最后加上了keys项。下面是当面对合法位置四周的位置是否加入队列的判断逻辑,记当前周围的一个待判断点为P(nx,ny):

  • 第一,需要保证P点在网格之内,同时该点不是墙,即不为”#”;
  • 第二,当P位置为.或者#时,如果有和当前一样的钥匙状态遍历过,则跳过,反之加入队列进行访问,并将访问状态加入visited;
  • 第三,当P点的值为大写字母,则代表是一把锁,如果当前的钥匙状态中有这把锁对应的钥匙,则可以将P点的信息加入到队列que中进行访问,并使用visited记录访问状态,反之跳过;
  • 第四,当P点的值为小写字母时,代表P点为钥匙,如果添加该钥匙后,已经有的钥匙数等于所有的钥匙数,则可以直接返回路径长度,程序结束,反之,如果P点的构建的状态没有访问过,则构建P点的遍历项加入队列que进行访问,并将访问记录添加到visied中。

最后,如果遍历所有的项都没有返回一条合法的路径长度,说明不存在这么一条路径,返回-1。

3.解题代码

Python代码(字符串标记钥匙状态)

from collections import dequeclass Solution:# BFS+字符串标记钥匙状态def shortestPathAllKeys(self, grid: List[str]) -> int:directions=[[-1,0],[0,-1],[1,0],[0,1]]rows,cols=len(grid),len(grid[0])# 第一步,将各个钥匙字符离散化为0,1,2...的数字sx,sy=0,0key2IndexMap={}for i in range(rows):for j in range(cols):if grid[i][j]=="@":sx,sy=i,jelif grid[i][j].islower():key2IndexMap[grid[i][j]]=len(key2IndexMap)# print(key2IndexMap)# 第二步,使用广度优先搜索遍历每个节点。BFS的使用队列存储遍历项,遍历的项为结构为(x坐标,y坐标,当前步数,当前已获取的钥匙的状态字符串),同时使用visited集合存储已经访问的不可重复状态,访问项结构为(x坐标,y坐标,当前已获取的钥匙的状态字符串);现将钥匙的状态字符串记为keys,keys[i]="1"代表已经获取到了离散值为i的钥匙,等于"0"则代表没有获取到。这里BFS的判断是否将下一个点(nx,ny)加入到队列的逻辑相对于普通的BFS更复杂,因为当碰到钥匙时,其前面的路径上的部分点是可以重复访问的,所以的前面的visited最后加上了keys项。下面是当面对合法位置四周的位置是否加入队列的判断逻辑,记当前周围的一个待判断点为P(nx,ny):第一,需要保证P点在网格之内,同时该点不是墙,即不为"#";第二,当P位置为.或者#时,如果有和当前一样的钥匙状态遍历过,则跳过,反之加入队列进行访问,并将访问状态加入visited;第三,当P点的值为大写字母,则代表是一把锁,如果当前的钥匙状态中有这把锁对应的钥匙,则可以将P点的信息加入到队列que中进行访问,并使用visited记录访问状态,反之跳过;第四,当P点的值为小写字母时,代表P点为钥匙,如果添加该钥匙后,已经有的钥匙数等于所有的钥匙数,则可以直接返回路径长度,程序结束,反之,如果P点的构建的状态没有访问过,则构建P点的遍历项加入队列que进行访问,并将访问记录添加到visied中。最后,如果遍历所有的项都没有返回一条合法的路径长度,说明不存在这么一条路径,返回-1。defaultKeys="0"*len(key2IndexMap)   # 字符串存储状态que=deque([(sx,sy,0,defaultKeys)])visited=set()while que:for i in range(len(que)):x,y,steps,oriKeys=que.popleft()for dx,dy in directions:keys=oriKeysnx,ny=x+dx,y+dyif 0<=nx<rows and 0<=ny<cols and grid[nx][ny]!="#":if grid[nx][ny] == "." or grid[nx][ny] == "@":# 没有参观的.和@能访问# print((nx,ny,steps+1,keys))if (nx,ny,keys) not in visited:que.append((nx,ny,steps+1,keys))visited.add((nx,ny,keys))elif grid[nx][ny].islower():# 如果没有这个钥匙,则访问keyIndex=key2IndexMap[grid[nx][ny]]# print((nx,ny,steps+1,keys))keys=keys[:keyIndex]+"1"+keys[keyIndex+1:]if (nx,ny,keys) not in visited:if keys=="1"*len(key2IndexMap):return steps+1que.append((nx,ny,steps+1,keys))visited.add((nx,ny,keys))else:   # 大写字母,表示是把锁# 如果这把锁没访问过且有对应的钥匙,则可以访问# print((nx,ny,steps+1,keys))matchKeyIndex=key2IndexMap[grid[nx][ny].lower()]if (nx,ny,keys) not in visited and keys[matchKeyIndex]=="1":que.append((nx,ny,steps+1,keys))visited.add((nx,ny,keys))# print()return -1

Python代码(二进制标记钥匙状态)

from collections import dequeclass Solution:# BFS+二进制标记钥匙状态def shortestPathAllKeys(self, grid: List[str]) -> int:directions=[[-1,0],[0,-1],[1,0],[0,1]]rows,cols=len(grid),len(grid[0])sx,sy=0,0key2IndexMap={}for i in range(rows):for j in range(cols):if grid[i][j]=="@":sx,sy=i,jelif grid[i][j].islower():key2IndexMap[grid[i][j]]=len(key2IndexMap)# print(key2IndexMap)defaultKeys=0   # 二进制存储状态que=deque([(sx,sy,0,defaultKeys)])visited=set()while que:for i in range(len(que)):x,y,steps,oriKeys=que.popleft()for dx,dy in directions:keys=oriKeysnx,ny=x+dx,y+dyif 0<=nx<rows and 0<=ny<cols and grid[nx][ny]!="#":if grid[nx][ny] == "." or grid[nx][ny] == "@":# 没有参观的.和@能访问# print((nx,ny,steps+1,keys))if (nx,ny,keys) not in visited:que.append((nx,ny,steps+1,keys))visited.add((nx,ny,keys))elif grid[nx][ny].islower():# 如果没有这个钥匙,则访问keyIndex=key2IndexMap[grid[nx][ny]]# print((nx,ny,steps+1,keys))keys=keys|(1<<keyIndex)if (nx,ny,keys) not in visited:if keys==(1<<len(key2IndexMap))-1:return steps+1que.append((nx,ny,steps+1,keys))visited.add((nx,ny,keys))else:   # 大写字母,表示是把锁# 如果这把锁没访问过且有对应的钥匙,则可以访问# print((nx,ny,steps+1,keys))matchKeyIndex=key2IndexMap[grid[nx][ny].lower()]if (nx,ny,keys) not in visited and keys&(1<<matchKeyIndex):que.append((nx,ny,steps+1,keys))visited.add((nx,ny,keys))# print()return -1

4.执行结果

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hello-Java-Sec 项目 (代码审计)

一、项目背景: Hello-Java-Sec项目为 Github中 一个面向安全开发的 Java漏洞代码审计靶场。 靶场地址:https://github.com/j3ers3/Hello-Java-Sec 本地使用idea部署即可二、代码审计: 通过阅读代码可知,代码采用 @RequestMapping 注解的方式来处理 HTTP不同方法的请求,故…

【原创】微信自动回复工具(下篇)

全文 离第一篇文章已经不知不觉过去3年多了,这段时间有空重新重构了一套消息回传模式,工具介绍官网: → → http://message.fuyue.xyz/ ← ← 视频演示: 观看视频 功能列表 本微信助手工具目前已经实现如下功能:接收微信好友消息 接收微信群组消息 接收系统消息(添加好友…

基于模糊神经网络的移动机器人路径规划matlab仿真

1.程序功能描述基于模糊神经网络的移动机器人路径规划 1.环境地图中的障碍物为静态、未知障碍物,可以随机设置。(一般设置5~7个,为计算简便设置成规则性状的障碍物) 2.机器人的行进方向为X轴的正方向,X轴逆时针旋转90即为Y轴。两驱动轮之间的距离为50cm,驱动轮的直径为30…

实验二

任务一 源代码1 #include <stdio.h>2 #include <time.h>3 4 #define N 55 #define N1 3976 #define N2 4767 #define N3 218 int main(){9 10 int random_major,random_no; 11 int cnt; 12 srand(time(NULL)); 13 14 cnt=0; 15 whil…

记录一次本地安装AI ollama大模型数据对话 的经历

浏览器打开 Ollama官网 下载对应的版本,我这里下载的 是对应 windows的版本,下载后直接运行安装安装完成后 打开 dos控制台,win+r,cmd那个,输入ollama 如果显示如下截图内容,就说明安装成功了,接下来就是下载 具体的 大数据库了 安装大模型前,建议先修改环境变量,因…

APP应用分发多个步骤和策略过程,如何进行app应用分发?

进行APP应用分发是一个涉及多个步骤和策略的过程,以下是对该过程的详细解析: 一、前期准备应用程序准备:开发人员需要确保应用程序已经经过完整的测试和质量保证,包括功能测试、用户体验测试、性能测试等,以确保其稳定性和可靠性。 打包应用程序,将开发完成的APP进行编译…

利用 ACME 实现SSL证书自动化配置更新

SSL 证书自动化最近收到腾讯云的通知SSL证书要到期了,本想直接申请的发现现在申请的免费SSL证书有效期只有90天了,顺便了解了一下原因是包括Google在内的国际顶级科技公司一直都有在推进免费证书90天有效期的建议,免费证书加密等级低,难以应对今天日益复杂的网络环境,90天…

arm imx6ull docker启动失败问题查找与解决 内核配置相关

arm imx6ull docker启动失败问题查找与解决 内核配置相关1、增加POSIX Message qeue:could not get initial namespace: no such file or directory CONFIG_POSIX_MQUEUE=y 2、增加namespace failed to set to initial namespace CONFIG_NAMESPACES=y 3、创建网络失败,veth配…

PictureBox实现进入换色,离开换色,点击换色

实现和Word标题栏类似的效果可以看到有三种颜色: 默认时是(243, 243, 243),鼠标进入时是这样(210, 210, 210),鼠标按下的瞬间变为了(177, 177, 177) 4个关键事件:MouseEnter、MouseLeave、MouseDown、MouseUp MouseEnter:在鼠标进入控件的可见部分时发生private void pictu…

Spring事务的1道面试题

每次聊起Spring事务,好像很熟悉,又好像很陌生。本篇通过一道面试题和一些实践,来拆解几个Spring事务的常见坑点。每次聊起Spring事务,好像很熟悉,又好像很陌生。本篇通过一道面试题和一些实践,来拆解几个Spring事务的常见坑点。 原理 Spring事务的原理是:通过AOP切面的方…

安装 Anaconda、PyTorch(GPU 版)库与 PyCharm

Anaconda 是一款巨大的 Python 环境集成平台,里面包含了 Python 解释器、Jupyter Notebook 代码编辑器以及很多的第三方库,所以安装 Anaconda 后我们无需再安装 Python 解释器,非常方便。 一、安装 Anaconda 1.卸载 Anaconda(可选) 如果我们原来的电脑上安装过 Anaconda,…

Ubuntu nginx 安装

1. 下载源码 下载页面:https://nginx.org/en/download.html 下载地址:https://nginx.org/download/nginx-1.27.2.tar.gz curl -O https://nginx.org/download/nginx-1.27.2.tar.gz 2. 依赖配置 sudo apt install gcc make libpcre3-dev zlib1g-dev openssl libssl-dev 3. 编译…