【图论刷题-5】力扣 1971. 寻找图中是否存在路径

图论刷题

  1. 机器人的运动范围
  2. 矩阵中的路径
  3. 图像渲染
  4. 水位上升的泳池中游泳
  5. 寻找图中是否存在路径

1971. 寻找图中是否存在路径

力扣原题 地址

难度与标签

简单难度

  • 深度优先遍历
  • 广度优先遍历
  • 并查找

题目描述

有一个具有 n 个顶点的 双向 图,其中每个顶点标记从 0n - 1(包含 0n - 1)。图中的边用一个二维整数数组 edges 表示,其中 edges[i] = [ui, vi] 表示顶点 ui 和顶点 vi 之间的双向边。 每个顶点对由 最多一条 边连接,并且没有顶点存在与自身相连的边。

请你确定是否存在从顶点 start 开始,到顶点 end 结束的 有效路径 。

给你数组 edges 和整数 nstartend,如果从 startend 存在 有效路径 ,则返回 true,否则返回 false

示例 1
在这里插入图片描述

输入:n = 3, edges = [[0,1],[1,2],[2,0]], start = 0, end = 2
输出:true
解释:存在由顶点 0 到顶点 2 的路径:
- 012 
- 02

示例2
在这里插入图片描述

输入:n = 6, edges = [[0,1],[0,2],[3,5],[5,4],[4,3]], start = 0, end = 5
输出:false
解释:不存在由顶点 0 到顶点 5 的路径.
  • 1 <= n <= 2 * 10^5
  • 0 <= edges.length <= 2 * 10^5
  • edges[i].length == 2
  • 0 <= ui, vi <= n - 1
  • ui != vi
  • 0 <= start, end <= n - 1
  • 不存在双向边
  • 不存在指向顶点自身的边

题目分析

理解起来比较容易,没有加一些花里胡哨的场景描述。与之前做的题比如 778. 水位上升的泳池中游泳 不同之处在于图的结构需要自己构建,给定的是所有的边。

所以首先构建图的结构然后去遍历寻找答案。

为了更加直观我绘制了图片如下:

给定的是 n = 6, edges = [[0,1],[0,2],[3,5],[5,4],[4,3]], 那么在构建这个图的时候可以是表示为多组向量,每一组向量的索引表示起点,向量中的元素表示为这个起点可达的元素,如图所示:

请添加图片描述
接着就从起点 X 开始,深度遍历规则与之前的那些区别不大。具体过程可以概述为:

寻找起点 X 对应的邻居向量 S,遍历 S 中每个 从未被访问过 的元素 W,如果 W == 目标Y,那么返回 true,否则继续访问 W 的邻居,重复整个步骤。

代码实现

class Solution {
public:
    /**
     * 初始化所有路径,根据题目中给定的矩阵,转换成一组一组的向量。
     */
    void initPath(const vector<vector<int>>& edges,
                  vector<vector<int>>& paths) {
        for (int i=0; i<edges.size(); i++) {
             int source = edges[i][0];
             int destination = edges[i][1];
             // 无向图,两个方向都要记录
             paths[source].push_back(destination);
             paths[destination].push_back(source);
        }
    }

    /**
     * 深度遍历,直到所有点都被访问或者从起点可达的路径都被访问
     */
    bool dfs(vector<vector<int>>& paths, 
             vector<bool>& visited, 
             int source,
             int destination) {
        // 标记已经被访问过
        visited[source] = true;
        // 达到目的地
        if (source == destination) {
            return true;
        }
        // 遍历source 为起点的所有可达邻居
        for (int i=0; i<paths[source].size(); i++) {
            int newSource = paths[source][i];
            // 如果这个点没有被访问过,则继续寻找它的邻居。
            if (!visited[newSource] && 
                dfs(paths, visited, newSource, destination)) {
                return true;
            }
        }
        return false;
    }

    bool validPath(int n, vector<vector<int>>& edges, int source, int destination) {
        
        vector<vector<int>> paths(n);
        vector<bool> visited(n, false);
        
        initPath(edges, paths);
        return dfs(paths, visited, source, destination);
    }
};

图的存储结构应该属于邻接表类型,因此时间复杂度与边的数目密切相关,如果边的数量为 e e e,点的数量为 n n n

  • 时间复杂度: O ( n + e ) O(n+e) O(n+e)
  • 空间复杂度: O ( n × e ) O(n\times e) O(n×e),即 p a t h s paths paths 变量占用的空间。

总结

题目简单但做起来感觉不那么容易,需要多思考,多回头看看。

Smileyan
2022.3.30 0:00

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

smile-yan

感谢您的支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值