当前位置: 首页 > news >正文

图论专题(三):“可达性”的探索——DFS/BFS 勇闯「钥匙和房间」

哈喽各位,我是前端小L。

欢迎来到我们的图论专题第三篇!我们已经学会了如何处理“显式”给出的图。但更多时候,图是作为一种“关系模型”,隐藏在问题描述的背后。

今天,我们将扮演一个“开锁达人”。我们手握0号房间的钥匙,每打开一扇门,都可能获得通往更多新门的钥匙。我们的目标是:判断我们能否“解锁”所有的房间。这,本质上是一个关于“可达性 (Reachability)”的经典图论问题。

力扣 841. 钥匙和房间

https://leetcode.cn/problems/keys-and-rooms/

题目分析:

  • 输入:一个 rooms 数组(列表的列表)。rooms[i] 是一个列表,存放着你在 i 号房间能找到的所有钥匙(即你能从 i 房打开哪些房门)。

  • 起点:你只能从 0 号房间开始。

  • 目标:判断是否可以访问所有房间。

“Aha!”时刻:将问题“翻译”成图论

  • 节点 (Vertex):每一个“房间 i” 都是图中的一个节点。

  • 边 (Edge):如果在 i 房能拿到 j 房的钥匙(jrooms[i] 列表中),这就代表一条从 ij有向边 (Directed Edge) i -> j

  • 建图:等等https://www.google.com/search?q=... rooms 数组 vector<vector<int>>rooms[i] 存着所有 i 能“到达”的节点。这不就是我们心心念念的“邻接表”吗!

  • 结论:这道题不需要我们“建图”rooms 数组本身就是图的邻接表

问题被完美转化: 给定一个有向图(由 rooms 描述),从节点 0 开始,我们能否遍历到图中的所有节点?

解决方案:DFS/BFS 的“标准作业”

既然问题是“可达性”,我们只需要从 0 号节点开始,用 DFS 或 BFS 进行一次“地毯式”的遍历,看看我们总共能访问到多少个节点。

我们还是需要那个“灵魂”—— visited 数组,来防止我们在0->1, 1->0 这样的环里“兜圈”。

算法流程:

  1. 获取房间总数 n

  2. 创建一个 visited 数组(或哈希集合),大小为 n,初始全为 false

  3. 创建一个 visited_count 计数器,初始为 0

  4. 启动遍历:从 0 号房间开始,执行一次 DFS 或 BFS。

    • 在 DFS/BFS 的过程中,每当你第一次访问一个房间 u 时:

      • visited[u] = true

      • visited_count++

    • 然后,探索 u 的所有邻居(即 rooms[u] 列表中的所有 key)。

  5. 检查结果:遍历结束后,比较 visited_count 是否等于 n

代码实现 (O(V+E) 时间, O(V) 空间)

解法一:DFS (递归)

C++

#include <vector>
#include <stack> // 也可以用递归栈using namespace std;class Solution {
private:int visited_count = 0;void dfs(int u, vector<vector<int>>& rooms, vector<bool>& visited) {// 1. 标记已访问visited[u] = true;visited_count++;// 2. 探索邻居for (int v_key : rooms[u]) {if (!visited[v_key]) {dfs(v_key, rooms, visited);}}}public:bool canVisitAllRooms(vector<vector<int>>& rooms) {int n = rooms.size();vector<bool> visited(n, false);// 从 0 号房间开始dfs(0, rooms, visited);// 检查是否访问了所有房间return visited_count == n;}
};

解法二:BFS (队列)

C++

#include <vector>
#include <queue>using namespace std;class Solution {
public:bool canVisitAllRooms(vector<vector<int>>& rooms) {int n = rooms.size();vector<bool> visited(n, false);queue<int> q;// 1. 启动 BFSq.push(0);visited[0] = true; // 入队时标记int visited_count = 1;while (!q.empty()) {int u = q.front();q.pop();// 2. 探索邻居for (int v_key : rooms[u]) {if (!visited[v_key]) {visited[v_key] = true; // 入队时标记q.push(v_key);visited_count++;}}}// 3. 检查结果return visited_count == n;}
};

深度复杂度分析

  • V (Vertices):顶点数,即 n (房间数)。

  • E (Edges):边数,即所有 rooms 列表中的“钥匙”总数。

  • 时间复杂度 O(V + E)

    • 建图:O(1),因为输入 rooms 本身就是邻接表。

    • 遍历 (DFS/BFS):我们访问每个房间(顶点 V)最多一次(visited 数组保证)。访问每个房间 i 时,我们会遍历 rooms[i] 列表,即遍历所有从 i 出发的“边”。

    • 整个遍历过程,我们访问了所有“可达”的顶点和所有从它们出发的“边”。最坏情况下,我们访问了所有 V 个顶点和所有 E 条边。

    • 总时间 O(V + E)。

  • 空间复杂度 O(V)

    • visited 数组:需要 O(V) 空间。

    • 辅助空间

      • DFS 需要 O(V) 的递归栈空间(最坏情况,如 0->1->...->n-1)。

      • BFS 需要 O(V) 的队列空间(最坏情况,如 0 号房有所有钥匙)。

    • 总空间 O(V)。

总结

今天,我们通过“钥匙和房间”这个生动的例子,学会了如何识别“隐式图”。 我们明白了,图的本质是“节点”和“关系”,只要题目中描述了这两种事物,它就可能是一个图论问题。

rooms 数组,就是一张从 irooms[i] 的有向图。我们的任务,就是从 0 开始,在这张图上“漫游”,看看能走多远。

在下一篇中,我们将把这个“漫游”的能力,应用到最常见的“隐式图”——二维网格上,去解决大名鼎鼎的“岛屿问题”!

下期见!

http://www.dtcms.com/a/604947.html

相关文章:

  • 图论专题(一):Hello, Graph! 掌握“建图”与“遍历”的灵魂
  • 做彩票网站能挣到钱吗中国最好的购物平台
  • 南京做网站群的公司岳西县住房和城乡建设局网站
  • 前端高频面试题之Vue(高级篇)
  • 【附源码】告别静态密码!openHiTLS 开源一次性密码协议(HOTP/TOTP),推动动态认证普及
  • UniApp 小程序中使用地图组件
  • 25华北理工大学考情数据分析
  • Unity Shader Graph 3D 实例 - 基础的模型贴图渲染
  • 17.TCP编程
  • Java高级特性:单元测试、反射、注解、动态代理
  • python机器学习工程化demo(包含训练模型,预测数据,模型列表,模型详情,删除模型)支持线性回归、逻辑回归、决策树、SVC、随机森林等模型
  • 逻辑回归在个性化推荐中的原理与应用
  • 织梦网站后台怎么登陆郑州知名做网站公司有哪些
  • 免费做网站的软件跨境电商自建站平台
  • 本机oracle连接延时41970 毫秒
  • 不到一块钱的带USB 2.4G收发 SOC芯片,集成2.4G射频 32位MCU
  • Ubuntu 24.04 安装 PostgreSQL
  • 数据科学每日总结--Day18--数据库
  • 【ZeroRange WebRTC】WebRTC 基于 STUN 的 srflx 直连原理与实现
  • neovim等模态编辑器最优雅的输入法解决方案
  • FaceBook叫板OpenAI!开源 Omnilingual ASR:支持1600多种语言的开源多语言语音识别
  • 分享一个MySQL万能备份脚本
  • 大模型数据洞察能力方法调研
  • 32位MCU芯片国产品牌(32系列单片机常用型号有哪些)
  • 网站底部留言代码赤峰建设淘宝网站
  • 方特网站是谁做的照片做视频的网站
  • Java 9 新特性详解
  • Spring boot 3.3.1 官方文档 中文
  • Sora 2——开启 AI 视频创作新时代
  • 异世界网络:BGP联邦的建立