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

news2024/11/24 23:08:37

题目描述

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

示例 1:

输入:n = 3, edges = [[0,1],[1,2],[2,0]], source = 0, destination = 2
输出:true
解释:存在由顶点 0 到顶点 2 的路径:

示例 2:

输入:n = 6, edges = [[0,1],[0,2],[3,5],[5,4],[4,3]], source = 0, destination = 5
输出:false
解释:不存在由顶点 0 到顶点 5 的路径.

提示:

  • 1 <= n <= 2 * 105
  • 0 <= edges.length <= 2 * 105
  • edges[i].length == 2
  • 0 <= ui, vi <= n - 1
  • ui != vi
  • 0 <= source, destination <= n - 1
  • 不存在重复边
  • 不存在指向顶点自身的边

方法一:并查集

  1. 思路:
  • 使用 并查集,依次遍历给定的 edges 数组 , 将存在双向边的两个点合并,最后在并查集中查询 source 和 destination 是否连通即可,如果他们不在一个集合,说明不连通。
  1. 情况
  • 通过;
  1. 收获
  • 我很快就想到了要用并查集的思想,这是我做题以来的进步,但还是有缺点,比如并查集模板我没有记下来,我是看着之前的题解又敲了一遍,还是要多做题。
  1. 时间复杂度:O(n + m * α(m)),n 是图中的顶点数,m 是图中边的数目, α 是反阿克曼函数。 并查集的初始化需要O(n)的时间,然后遍历 m 条边并执行 m 次合并操作,最后对 source 和 destination 进行一次查询操作。查询与合并的单次操作时间复杂度是O(α(m)),因此合并和查询的时间复杂度为 O(m * α(m)),总的时间复杂度为 O(n + m * α(m))。
    空间复杂度:O(n),n 为节点数量;
    在这里插入图片描述
class UF{
public:
    vector<int> fa; // 存储每个节点的父节点
    vector<int> sz; // 只有节点是祖宗节点的时候才有意义,表示祖宗节点所在集合的节点数
    int n; // 节点数量
    int comp_cnt;

public:
    // 有参数的构造函数
    UF(int n_): n(n_), comp_cnt(n_), fa(n_), sz(n_, 1){
        // iota 自增函数
        iota(fa.begin(), fa.end(), 0);
    }

    // 寻找元素x的集合的祖宗节点
    int findset(int x){
        return fa[x] == x ? x : fa[x] = findset(fa[x]);
    }

    // 合并
    bool unite(int x, int y){
        // 寻找各自的祖宗节点
        x = findset(x);
        y = findset(y);
        if(x == y) return false; // 无需合并

        // 合并
        // 确保合并到元素较多的集合中
        if(sz[x] < sz[y]) swap(x, y);
        fa[y] = x;
        sz[x] += sz[y];
        -- comp_cnt;
        return true;  
    }

    // 判断x和y是否在同一集合里
    bool connected(int x, int y){
        x = findset(x);
        y = findset(y);
        return x == y;
    }
};
class Solution {
public:
    bool validPath(int n, vector<vector<int>>& edges, int source, int destination) {
        UF uf(n);
        for(vector<int>& e : edges){
            uf.unite(e[0], e[1]);
        }
        return uf.connected(source, destination);
    }
};

方法二:DFS

  1. 思路:
  • 先将 edges 转换成图 g , 然后使用 DFS ,判断是否存在从 source 到 destination 的路径。
  • 数组 visit 记录已经访问过的顶点,避免重复访问。
  • 首先从顶点 source 开始遍历并进行递归搜索。搜索时每次访问一个顶点 ,如果顶点等于 destination 则直接返回,否则将该顶点设置为已访问,并递归访问与该顶点相邻且未访问的顶点next ,如果通过 next 的路径可以访问到 destination ,此时直接返回 true , 当访问完所有的邻接节点仍然没有访问到 destination ,此时返回 false。
  1. 情况
  • 通过;
  1. 收获
  • 这道题的关键点是,对于 DFS 函数中,visit数组必须以引用的方式传入 ,否则会超时。
    引用的一个重要作用就是作为函数的参数,如果有大的数据作为参数传递的时候,往往采取指针传递,因为这样可以避免较多的数据压栈,可以提高程序效率
  1. 时间复杂度:O(n + m)。其中 n 是图中顶点数目, m 表示图中边的数目。对于图中的每个顶点或者每条边,我们最多只需要访问一次,因此时间复杂度为O(n + m) 。
    空间复杂度:O(n + m),其中 n 是图中顶点数目, m 表示图中边的数目。空间复杂度取决于邻接顶点列表、记录每个顶点访问状态的数组和递归调用栈, 邻接顶点列表需要O(m + n)的存储空间,记录每个顶点访问状态的数组和递归调用栈分别需要 O(n)的空间,因此总的空间复杂度为 O(m + n)。
    在这里插入图片描述
class Solution {
public:
    bool DFS(int source, int destination, vector<vector<int>>& g, vector<bool> &visit){
        if(source == destination)   return true;
        visit[source] = true;
        for(int next : g[source]){
            if(!visit[next] && DFS(next, destination, g, visit)){
                return true;
            }
        }
        return false;
    }
    bool validPath(int n, vector<vector<int>>& edges, int source, int destination) {
        vector<vector<int>> g(n); // 图数组
        // 将 edges 转为 图
        for(auto& e : edges){
            int a = e[0], b = e[1];
            g[a].emplace_back(b);
            g[b].emplace_back(a);
        }
        vector<bool> visit(n, false); // 数组是否被访问过
        
        return DFS(source, destination, g, visit);
    }
};

方法三:BFS

  1. 思路:
  • 先将 edges 转换成图 g , 然后使用 BFS ,判断是否存在从 source 到 destination 的路径。
  • 数组 visit 记录已经访问过的顶点,避免重复访问。
  • 遍历过程我们使用队列存储最近访问过的顶点,同时记录每个顶点的访问状态,每次从队列中取出顶点 vertex 时,将其未访问过的邻接顶点入队列。
  • 初始时将顶点 source 设为已访问,,并将其入队列。每次将队列中的节点 vertex 出队,并将与 vertex 相邻且未访问的顶点 next 入队,并将 next 设为已访问。当队列为空或访问到顶点 destination 时遍历结束 ,返回顶点 destination 的访问状态即可。
  1. 情况
  • 通过;
  1. 收获
  • 通过这道题复习了 BFS,广度优先搜索;
  1. 时间复杂度:O(n + m)。其中 n 是图中顶点数目, m 表示图中边的数目。对于图中的每个顶点或者每条边,我们最多只需要访问一次,因此时间复杂度为O(n + m) 。
    空间复杂度:O(n + m),其中 n 是图中顶点数目, m 表示图中边的数目。空间复杂度取决于邻接顶点列表、记录每个顶点访问状态的数组和队列, 邻接顶点列表需要O(m + n)的存储空间,记录每个顶点访问状态的数组需要 O(n)的空间,进行广度搜索时队列最多只有 n 个元素,因此总的空间复杂度为 O(m + n)。
    在这里插入图片描述
class Solution {
public:
    bool validPath(int n, vector<vector<int>>& edges, int source, int destination) {
        vector<vector<int>> g(n); // 图数组
        // 将 edges 转为 图
        for(auto& e : edges){
            int a = e[0], b = e[1];
            g[a].emplace_back(b);
            g[b].emplace_back(a);
        }
        vector<bool> visit(n, false); // 数组是否被访问过
        queue<int> q;
        q.emplace(source);
        visit[source] = true;
        while(!q.empty()){ // 当队列不为空时
            int vertex = q.front();
            q.pop();
            if(vertex == destination) break;
            for(int next : g[vertex]){
                if(!visit[next]){ // 如果该点未被访问
                    q.emplace(next);
                    visit[next] = true;
                }
            }
        }       
        return visit[destination];
    }
};

参考文献:

  1. DFS算法原理及其具体流程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/100139.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

犀牛插件开发-基础核心-技术概览-总体架构-教程

文章目录1.概述2.基础核心2.1.C Rhino 核心2.2.openNURBS2.3.C SDK3.C Stack3.1.C Plugins3.2.RhinoScript4.NET Stack4.1.C API4.2.NET Framework4.3.RhinoCommon4.4.Eto4.5.net插件4.6.Grasshopper组件4.7.Python脚本5.相关主题1.概述 《Rhinoceros》由许多层组成——用多种…

细说OA系统的繁荣发展

改革开放以来&#xff0c;科技发展突飞猛进&#xff0c;我们生活的方方面面都受到了巨大影响。随着信息化时代的到来&#xff0c;企业的办公方式也发生了巨大的改变&#xff0c;OA系统随之走进了大众的视野。细数这四十几年&#xff0c;OA办公系统已经由一个异想天开的想法变成…

centos7.8离线安装pg和postgis

安装包下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1MxJc-5Ws6OPTRAoC-2srJw 提取码&#xff1a;is2q 1.centos7.8 离线安装pg操作步骤 这里基于centos7.8空白系统操作实践写的文档&#xff0c;系统一致的情况下可以照搬教程操作安装&#xff0c;镜像为…

1.0、Hibernate-快速入门初体验

1.0、Hibernate-快速入门初体验 Hibernate 和 mybatis 一样是 ORM (Object Relation Mapping) 对象关系映射框架&#xff0c;将面向对象映射成面向关系。 如何使用呢&#xff1f; 1、导入依赖&#xff1b; 2、创建 Hibernate 配置文件&#xff1b; 3、创建实体类&#xff1b; 4…

Allegro172版本多人协同在线设计操作指导

Allegro172版本多人协同在线设计操作指导 Allegro升级到172版本,可以支持多人协同设计,并且实时同步,具体操作如下 首先用户需要在同一个局域网下,并且Allegro172的版本必须一致,比如都是S082的版本 第一个用户打开PCB,选择Symphony Team design 选择 Start Symphony …

2022年度总结

自我介绍 大家好&#xff0c;我又回来了&#xff01;我在一年之前在 CSDN 写了第一篇文章&#xff0c;到现在也有一年时间了。这次回来呢&#xff0c;也是因为 CSDN 官方发的消息&#xff0c;让写一篇年度总结的文章。在离开的这几个月里&#xff0c;主要是因为工作繁忙&#…

ASO优化:总结APP被下架的5点原因

随着苹果的App Store的监管力度的不断加强&#xff0c;每个APP都会有被下架的风险&#xff0c;而对于开发者来说&#xff0c;APP被下架是一件很严重的事情&#xff0c;不仅会造成用户的流失&#xff0c;还会降低用户对APP 的信任。所以&#xff0c;我们要了解APP被下架的原因&a…

【大数据技术Spark】Spark SQL操作Dataframe、读写MySQL、Hive数据库实战(附源码)

需要源码和依赖请点赞关注收藏后评论区留言私信~~~ 一、Dataframe操作 步骤如下 1&#xff09;利用IntelliJ IDEA新建一个maven工程&#xff0c;界面如下 2&#xff09;修改pom.XML添加相关依赖包 3&#xff09;在工程名处点右键&#xff0c;选择Open Module Settings 4&a…

整数的大小端序

在存储整数时&#xff0c;一般按字节为逻辑单位进行存储&#xff0c;有“小端序”和“大端序”之分。小端序&#xff08;little-endian&#xff09; 是指将表示整数的低位字节存储在内存地址的低位&#xff0c;高位字节存储在内存地址的高位。如果将整数 1982062410 存储至内存…

【CANN训练营第三季】2022年度第三季新手班之昇腾AI入门课

本次参加CANN训练营&#xff0c;本来我报名的是进阶班课程&#xff0c;再看一遍新手班&#xff0c;学习一下目前CANN的最新进展也是不错的&#xff0c;巩固一下。 视频课程大家可以从这里看到 &#xff08;1&#xff09;【CANN训练营第三季】- 昇腾AI入门课&#xff08;上&am…

使用Keepalived工具实现集群节点的高可用

GreatSQL社区原创内容未经授权不得随意使用&#xff0c;转载请联系小编并注明来源。GreatSQL是MySQL的国产分支版本&#xff0c;使用上与MySQL一致。作者&#xff1a;蟹黄瓜子文章来源&#xff1a;社区投稿 1.前言 在集群当中离不开的一个词就是是高可用&#xff0c;用本文来…

OpenWrt + 每步科技DDNS 实现ipv6动态域名解析方法

其实好几个月前我就已经把这个动态域名设置好了&#xff0c;后面重新刷了系统&#xff0c;忘记保存&#xff0c;又得重新再来&#xff0c;这次把过程记录一下&#xff0c;免得下次再从头百度。 工具 刷好openWrt的路由器一个每步科技注册的域名&#xff08;我为什么选择这个&…

数字电子技术(八)D/A和A/D转换

D/A和A/D转换概述D/A转换A/D转换例题练习模拟信号&#xff1a;在时间与数值上都连续 数字信号&#xff1a;在时间与数值上都离散 概述 D/A转换&#xff1a;数字信号——模拟信号 &#xff08;D/A转换器简称DAC&#xff09;A/D转换&#xff1a;模拟信号——数字信号 &#xff0…

修改物料编号格式及长度

修改物料编号格式及长度(OMSL) 路径&#xff1a;IMG--后勤常规--物料主数据--基本设置--定义物料编号的输出格式

毕业设计 - 基于JSP的合同信息管理系统【源码+论文】

文章目录前言一、项目设计1. 模块设计数据库设计2. 实现效果二、部分源码项目源码前言 今天学长向大家分享一个 java web jsp 项目: 基于JSP的合同信息管理系统 适合用于毕业设计、课程设计 一、项目设计 1. 模块设计 需求分析是从客户的需求中提取出软件系统能够帮助用户…

java互联网医院系统HIS源码带本地搭建教程

技术架构 技术框架&#xff1a;SpringBoot MySql MyBatis nginx Vue2.6 原生APP 运行环境&#xff1a;jdk8 IntelliJ IDEA maven 宝塔面板 Android Studio 文字本地搭建教程 下载源码&#xff0c;小皮面板安装mysql5.7数据库&#xff0c;创建一个新数据库&#xff0c;…

引力波探测,冷冻电镜研究:两项诺奖GPU功不可没

我们的日常工作固然重要&#xff0c;但并非每一份重要的工作都能够助力他人获得诺贝尔奖。然而&#xff0c;就在2017年10月&#xff0c;GPU 计算便两度成为了助力获得诺贝尔奖的幕后英雄。 三名美国物理学家Rainer Weiss、Barry Barish和Kip Thorne因探测到了爱因斯坦百年前预测…

从“跨域融合”到“中央计算”,这家Tier1如何率先抢跑?

全球汽车产业已经进入以智能化为主旋律的下半场竞赛&#xff0c;同时整车电子电气架构也在加速跨入集中式电子电气架构时代。 在这样的背景之下&#xff0c;智能驾驶域控制器成为了当前最大的增量市场之一&#xff0c;由此也带动了上游芯片、OS、中间件等域控相关软硬件产品的…

第13讲:Python列表对象中元素的删操作

文章目录1.列表元素删操作的方法2.调用remove方法一次删除一个指定的元素3.调用pop方法一次只删除一个指定索引的元素3.1.使用pop方法删除列表中索引为2的元素3.2.使用pop方法不指定索引3.3.使用pop方法指定的索引不存在时同样也会抛出错误4.使用del语句一次至少删除一个元素4.…

nodejs+vue082新生入学管理系统-vscode msyql

一章 绪论 3 1.1课题背景 3 1.2课题研究的目的和意义 3 1.3 研究现状 4 1.4论文所做的主要工作 4 第二章 技术介绍 5 2.1 B/S结构 5 2.2MySQL介绍 5 2.3MySQL环境配置 6 第三章 系统分析与设计 8 3.1系统说明 8 3.2系统可行性分析 8 3.2.1 技术可行性 8 3.2.2 经济可行性 8 3…