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

图解 BFS 路径搜索:LeetCode1971

图解 BFS 路径搜索:LeetCode

  • 题目描述:有一个具有 n 个顶点的 双向 图,其中每个顶点标记从 0 到 n - 1(包含 0 和 n - 1)。图中的边用一个二维整数数组 edges 表示,其中 edges[i] = [ui, vi] 表示顶点 ui 和顶点 vi 之间的双向边。 每个顶点对由 最多一条 边连接,并且没有顶点存在与自身相连的边。请你确定是否存在从顶点 source 开始,到顶点 destination 结束的 有效路径 。

  • 给你数组 edges 和整数 n、source 和 destination,如果从 source 到 destination 存在 有效路径 ,则返回 true,否则返回 false 。

在这里插入图片描述

在图论算法中,判断节点连通性与收集所有路径是经典场景。本文围绕无向图,结合具体代码,深入拆解判断两节点是否连通(validPath收集两节点间所有路径(allPaths 的实现逻辑,以输入 n = 3, edges = [[0,1],[1,2],[2,0]], source = 0, destination = 2 为例,清晰展现广度优先搜索(BFS)的运作流程。

一、基础准备:图的邻接表构建

无论判断连通还是收集路径,第一步需将图的边结构转换为邻接表,方便后续遍历。代码中通过 create_tree_node 方法实现:

void create_tree_node(int n, vector<vector<int>>& edges) {adj.resize(n); for (const auto& edge : edges) {int u = edge[0], v = edge[1];adj[u].push_back(v); adj[v].push_back(u); }
}

逻辑拆解(以输入为例):

  • 初始化:adj.resize(3) 为节点 012 各分配一个 vector<int> 存储邻居。
  • 遍历边:每条边双向存邻接表,如边 [0,1] 会让 adj[0] 加入 1adj[1] 加入 0 。最终邻接表状态:
    adj[0] = [1, 2]; adj[1] = [0, 2]; adj[2] = [1, 0];
    

二、判断两节点是否连通(validPath 逻辑)

目标:检查从 sourcedestination 是否存在至少一条路径,用 BFS 实现“层序遍历 + 访问标记”。

核心代码回顾

bool validPath(int n, vector<vector<int>>& edges, int source, int destination) {create_tree_node(n, edges); vector<bool> visited(n, false); queue<int> q; q.push(source); visited[source] = true; while (!q.empty()) {int current = q.front(); q.pop(); if (current == destination) return true; for (int neighbor : adj[current]) { if (!visited[neighbor]) {visited[neighbor] = true; q.push(neighbor); }}}return false; 
}

流程拆解(输入 source=0, destination=2

  1. 初始化visited 标记数组全为 false;队列 q 放入 0,并标记 visited[0] = true
  2. 第一次循环
    • 取出 current = 0,检查是否是 2 → 否。
    • 遍历 adj[0] 邻居 [1, 2]
      • 1 未访问 → 标记 visited[1]=true,入队 q = [1]
      • 2 未访问 → 标记 visited[2]=true,入队 q = [1, 2]
  3. 第二次循环
    • 取出 current = 1,检查是否是 2 → 否。
    • 遍历 adj[1] 邻居 [0, 2]
      • 0 已访问 → 跳过;2 已访问 → 跳过。
  4. 第三次循环
    • 取出 current = 2,检查是否是 2 → 是!返回 true,流程结束。

三、收集两节点间所有路径(allPaths 逻辑)

目标:找到从 sourcedestination全部路径,需用“路径驱动的 BFS”,队列存储完整路径。

核心代码回顾

vector<vector<int>> allPaths(int n, vector<vector<int>>& edges, int source, int destination) {create_tree_node(n, edges); vector<vector<int>> result; queue<vector<int>> q; q.push({source}); while (!q.empty()) {vector<int> path = q.front(); q.pop(); int current = path.back(); if (current == destination) {result.push_back(path); continue; }for (int neighbor : adj[current]) { bool is_cycle = false; for (int node : path) { if (node == neighbor) { is_cycle = true; break; }}if (!is_cycle) { vector<int> newPath = path; newPath.push_back(neighbor); q.push(newPath); }}}return result; 
}

流程拆解(输入 source=0, destination=2

  1. 初始化:结果集 result 为空;队列 q 放入初始路径 {0}
  2. 第一次循环
    • 取出路径 path = {0}current = 0(路径末尾节点)。
    • 检查是否是 2 → 否。
    • 遍历 adj[0] 邻居 [1, 2]
      • 邻居 1:路径 {0} 中无 1 → 构造新路径 {0,1},入队 q = [ {0,1} ]
      • 邻居 2:路径 {0} 中无 2 → 构造新路径 {0,2},入队 q = [ {0,1}, {0,2} ]
  3. 第二次循环
    • 取出路径 path = {0,1}current = 1
    • 检查是否是 2 → 否。
    • 遍历 adj[1] 邻居 [0, 2]
      • 邻居 0:路径 {0,1} 中已有 0 → 跳过(防环)。
      • 邻居 2:路径 {0,1} 中无 2 → 构造新路径 {0,1,2},入队 q = [ {0,2}, {0,1,2} ]
  4. 第三次循环
    • 取出路径 path = {0,2}current = 2 → 是目标!加入 resultresult = [ {0,2} ]
  5. 第四次循环
    • 取出路径 path = {0,1,2}current = 2 → 是目标!加入 resultresult = [ {0,2}, {0,1,2} ]

四、关键逻辑对比与总结

场景核心思路队列存储内容终止条件适用场景
判断连通(validPath节点驱动 BFS,标记访问状态单个节点找到目标节点立即返回只需判断是否连通
收集所有路径(allPaths路径驱动 BFS,防环扩展路径完整路径收集所有到达目标的路径需枚举全部路径场景

两种实现均基于 BFS 思想,但因目标不同,队列存储与逻辑分支有明显差异。邻接表的双向边处理(无向图特性)、访问标记/防环逻辑,是确保算法正确的关键。

通过本文拆解,可清晰理解 BFS 在图论问题中的灵活应用——从简单连通性判断,到复杂路径收集,核心逻辑的扩展与适配思路值得反复揣摩。

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

相关文章:

  • 芯片I/O脚先于电源脚上电会导致Latch-up(闩锁效应)吗?
  • Logback日志框架配置实战指南
  • 5种使用USB数据线将文件从安卓设备传输到电脑的方法
  • 【JavaScript 函数、闭包与 this 绑定机制深度解析】
  • 【C语言】指针笔试题2
  • 模块三:现代C++工程实践(4篇)第二篇《性能调优:Profile驱动优化与汇编级分析》
  • FlashAttention 快速安装指南(避免长时间编译)
  • QT网络通信底层实现详解:UDP/TCP实战指南
  • Centos 7下使用C++使用Rdkafka库实现生产者消费者
  • 【LeetCode 热题 100】19. 删除链表的倒数第 N 个结点——双指针+哨兵
  • 学习 Flutter (一)
  • html的outline: none;
  • C++STL-deque
  • 1. COLA-DDD的实战
  • 【基础架构】——软件系统复杂度的来源(低成本、安全、规模)
  • 告别卡顿与慢响应!现代 Web 应用性能优化:从前端渲染到后端算法的全面提速指南
  • IDEA运行Spring项目报错:java: 警告: 源发行版 17 需要目标发行版 17,java: 无效的目标发行版: 17
  • Cargo.toml 配置详解
  • 【科研绘图系列】R语言探索生物多样性与地理分布的可视化之旅
  • 网安-解决pikachu-rce乱码问题
  • 访问Windows服务器备份SQL SERVER数据库
  • (C++)任务管理系统(文件存储)(正式版)(迭代器)(list列表基础教程)(STL基础知识)
  • x86交叉编译ros 工程给jetson nano运行
  • Rust and the Linux Kernel
  • Sophix、Tinker 和 Robust 三大主流 Android 热修复框架的详细对比
  • windows10 安装docker到H盘
  • Linux 服务器挖矿病毒深度处理与防护指南
  • 使用Docker将Python项目部署到云端的完整指南
  • Web 会话认证方案详解:原理、流程与安全实践
  • Variables