《程序员面试金典(第6版)》面试题 04.01. 节点间通路

题目描述

节点间通路。给定有向图,设计一个算法,找出两个节点之间是否存在一条路径。

示例1:

  • 输入:n = 3, graph = [[0, 1], [0, 2], [1, 2], [1, 2]], start = 0, target = 2
    输出:true

示例2:

  • 输入:n = 5, graph = [[0, 1], [0, 2], [0, 4], [0, 4], [0, 1], [1, 3], [1, 4], [1, 3], [2, 3], [3, 4]], start = 0, target = 4
    输出 true

提示:
节点数量n在[0, 1e5]范围内。
节点编号大于等于 0 小于 n。
图中可能存在自环和平行边。

解题思路与代码

做这道题之前,需要你对DFS(深度优先算法),BFS(广度优先算法),邻接表(一种存储结构),有向图(图的一种,是一种数据结构)有着一些基本的了解。否则你光干瞪着眼看题,是看不出什么结果的。

首先从头来解释一下这道题,首先题目给的graph是一个二维数组,其中的每一个元素都是一个存储着两个元素的vector。vector中的每一个不重复的数字,都代表着一个节点。每一个vector中都有两个元素,将这两个元素想象成两个节点,那就是第一个节点指向第二个节点。

将graph中的每一个节点的指向都画出来的话,你就可以得到一张有向图

邻接表 + DFS

首先,我们需要题目给的有向图去存储到邻接表之中去。那么存储图的邻接表的代码长这样:

 vector<vector<int>> vec(n); 

其中n就是节点的个数啦。可以想象,邻接表就是将图中的每一个节点都当做一个链表,节点本身就是链表的头节点。后面连着几个节点,我们就将这些节点添加到头节点对应的vector中去。

那这道题解题的第一步就是,将图按照邻接表的形式存储在vector中。

第二步就是深度优先遍历,深度优先遍历的本质上是递归。因为我们都知道了,二维vector中的每一个vector都代表着一条路线。我们只需要将每条路线都一一走到头,就能判断出来,有没有题目中给出的start -> target的这条路线了。

具体的代码如下:

class Solution {
public:// 邻接表+DFS
    bool findWhetherExistsPath(int n, vector<vector<int>>& graph, int start, int target) {
        
        // 初始化邻接表为容量为n的二维向量, 存储有向边
        vector<vector<int>> vec(n); // 外面的这个vector有n个元素,都是vector

        // 将图中的有向边存入邻接表Vec
        for (const auto& g : graph) { //g是一个vector,里面存放了两个元素。
            vec[g[0]].push_back(g[1]);//下标为g[0]的vector中添加了一个数字,这个数字是g[1]
        }

        // 调用dfs函数,执行深度优先搜索
        return dfs(vec, start, target);
    }

    bool dfs( vector<vector<int>>& vec, int start, int target) {
        // 如果起点和终点相同,则存在连通路径,返回true
        if (start == target) {
            return true;
        }

        // 依次遍历从起点可直接到达的节点v,递归地调用函数,并以v为新起点进行下一轮搜索
        for (const auto& v : vec[start]) { //这个vec[start]本身代指的是一个一维数组。
            if(dfs( vec, v, target)) {
                return true;
            }
        }

        // 若所有路径都走不到终点,则不存在连通路径,返回false
        return false;
    }
};
复杂度分析

时间复杂度:

对于邻接表的创建,需要遍历一次整个图中所有的边,其时间复杂度为 O(E),其中 E 表示边数。
对于 DFS 遍历,每一个点最多只会被访问一次,在最坏情况下,需要访问图中所有的点,因此其时间复杂度为 O(n),其中 n 表示点数。
综上所述,该算法的时间复杂度为 O(E + n)。
空间复杂度:

邻接表使用了一个二维向量来存储边信息,其大小为 O(E),其中 E 表示边数。由于 E 不超过 n^2 的级别,因此该向量的空间需求不会超过 O(n^2)。
在 DFS 的递归调用过程中,根据深度可能会生成 O(n) 个递归层级。而每一层递归函数在栈中占用的空间是常数级别的 O(1),因此 DFS 所需要的空间是 O(n) 级别的。
综上所述,该算法的空间复杂度为 O(n^2+n),即 O(n^2) 级别。
因此,总的来说,该算法的时间复杂度为 O(E+n),空间复杂度为 O(n^2)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

阿宋同学

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值