【LeetCode】841. 钥匙和房间

841. 钥匙和房间

知识点:图;递归;BFS

题目描述

有 N 个房间,开始时你位于 0 号房间。每个房间有不同的号码:0,1,2,...,N-1,并且房间里可能有一些钥匙能使你进入下一个房间。

在形式上,对于每个房间 i 都有一个钥匙列表 rooms[i],每个钥匙 rooms[i][j] 由 [0,1,...,N-1] 中的一个整数表示,其中 N = rooms.length。 钥匙 rooms[i][j] = v 可以打开编号为 v 的房间。

最初,除 0 号房间外的其余所有房间都被锁住。

你可以自由地在房间之间来回走动。

如果能进入每个房间返回 true,否则返回 false。

示例
输入: [[1],[2],[3],[]] 输出: true 解释: 我们从 0 号房间开始,拿到钥匙 1 之后我们去 1 号房间,拿到钥匙 2 然后我们去 2 号房间,拿到钥匙 3 最后我们去了 3 号房间。 由于我们能够进入每个房间,我们返回 true 输入:[[1,3],[3,0,1],[2],[0]] 输出:false 解释:我们不能进入 2 号房间。

解法一:深度优先(DFS)

当 x 号房间中有 y 号房间的钥匙时,我们就可以从 x 号房间去往 y 号房间。如果我们将这 n 个房间看成有向图中的 n 个节点,那么上述关系就可以看作是图中的 x 号点到 y 号点的一条有向边。

这样一来,问题就变成了给定一张有向图,询问从 0 号节点出发是否能够到达所有的节点。

深度优先的意思就是先进入第一个房,然后拿出第一把钥匙,去开下一个房,然后再拿到这个房的第一个钥匙,再去开下一个,直到没钥匙了,退回上一个房,重复以往。这是一个递归的过程,和二叉树的遍历一样。

可以用一个数组来记录到达过哪个房间,防止重复计算。
函数功能:遍历房间
1.终止条件:把第0个房间的钥匙拿完;
2.该做什么:每个房间应该做什么呢,判断数组标志那个房间去过没有,去过了就跳过,没去过就进去,并把标志位置为true。计数器加1.最后看是否等于房间个数。

class Solution { boolean[] vis; int num = 0; public boolean canVisitAllRooms(List<List<Integer>> rooms) { int n = rooms.size(); vis = new boolean[n]; //设置第n个房间是否打开过的标志位; canVisitAllRooms(rooms, 0); return num == n; //查看是否遍历完; } private void canVisitAllRooms(List<List<Integer>> rooms, int roomnum){ vis[roomnum] = true; num++; for(int i : rooms.get(roomnum)){ if(!vis[i]){ //没有访问过就进去; canVisitAllRooms(rooms, i); } } } }

解法二:广度优先(BFS)

广度优先的意思就是我们不拿到一个钥匙走到头了,我们一个房间一个房间的进,拿到第一个房间的钥匙,把第一个房间里的钥匙对应的门都打开,然后再去第二个房间。这样一个一个的进。

class Solution { public boolean canVisitAllRooms(List<List<Integer>> rooms) { int n = rooms.size(); boolean[] vis = new boolean[n]; //标志位就是防止被重复遍历; int num = 0; Queue<Integer> queue = new LinkedList<>(); vis[0] = true; //设置0号访问过,为了防止节点多次入队,需要在入队前将其设置为已访问; queue.add(0); //0号房间入队; while(!queue.isEmpty()){ int x = queue.poll(); num++; for(int i : rooms.get(x)){ if(!vis[i]){ //没有被访问过; vis[i] = true; queue.add(i); //保证入队的都是没有被遍历过的; } } } return n == num; } }

体会

  • 1.只要是广度优先的,肯定要用队列,天然是在一起的。 一边弹出,一边遍历,弹出一个以后,就把它的孩子或者是它的关联入队,保证把这一层,或这个节点的都弹出了,接着继续弹下一层或者下一个节点的。
  • 2.树的BFS:先把root节点入队,然后再一层一层的遍历。
    图的BFS也是一样的,与树的BFS的区别是:
    • 1.树只有一个root,而图可以有多个源点,所有首先需要将多个源点入队。
    • 2.树是有向的因此不需要标志是否访问过,而对于无向图而言,必须得标志是否访问过!并且为了防止某个节点多次入队,需要在入队前将其设置为已访问!
  • 3.树用DFS比较多,图用BFS比较多;

相关题目

133. 克隆图
1162. 地图分析


__EOF__

本文作者Curryxin
本文链接https://www.cnblogs.com/Curryxin/p/15092786.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Curryxin  阅读(207)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
Live2D
欢迎阅读『【LeetCode】841. 钥匙和房间』
点击右上角即可分享
微信分享提示