( “ 图 “ 之 并查集 ) 684. 冗余连接 ——【Leetcode每日一题】

news2024/11/18 5:30:32

❓684. 冗余连接

难度:中等

树可以看成是一个连通且 无环无向 图。

给定往一棵 n 个节点 (节点值 1~n ) 的树中添加一条边后的图。添加的边的两个顶点包含在 1n 中间,且这条附加的边不属于树中已存在的边。图的信息记录于长度为 n 的二维数组 edgesedges[i] = [ai, bi] 表示图中在 aibi 之间存在一条边。

请找出一条可以删去的边,删除后可使得剩余部分是一个有着 n 个节点的树。如果有多个答案,则返回数组 edges 中最后出现的边。

示例 1:

在这里插入图片描述

输入: edges = [[1,2], [1,3], [2,3]]
输出: [2,3]

示例 2:

在这里插入图片描述

输入: edges = [[1,2], [2,3], [3,4], [1,4], [1,5]]
输出: [1,4]

提示:

  • n == edges.length
  • 3 <= n <= 1000
  • edges[i].length == 2
  • 1 <= ai < bi <= edges.length
  • ai != bi
  • edges 中无重复元素
  • 给定的图是连通的

💡思路:并查集

树是一个连通且无环的无向图,在树中多了一条附加的边之后就会出现环,因此附加的边即为导致环出现的边。

  • 可以通过并查集寻找附加的边。并查集可以动态地连通两个点,并且可以非常快速地判断两个点是否连通。

并查集的基本思想是维护一个森林,每个集合对应一棵树,树的根节点表示该集合的代表元素。初始时,每个元素都是一个单独的集合,对应一棵只包含自己的树。合并操作可以将两棵树合并为一棵树,查找操作可以找到某个元素所在的树的根节点。

我们可以使用一个一位数组parents存储每个节点的根节点,即根节点的数组下标,以例2举例,如下图:

在这里插入图片描述

并查集最主要的是就是以下两种操作

  1. 查找操作:查找某个元素所属的集合,即查找该元素所在数的根节点(祖先)。
  2. 合并操作:将两个集合合并为一个集合,祖先不同,则合并:
    • 合并时可以通过路径压缩来优化时间复杂,就是如果两个根节点的深度不同,就让深度小的根节点的祖先等于深度较大的节点,从而使整颗树不会太深,查找祖先时间不会太长,平均时间为 O ( l o g n ) O(logn) O(logn)

🍁代码:(Java、C++)

Java

class Solution {
    private int[] ans = new int[2];
    public int[] findRedundantConnection(int[][] edges) {
        int n = edges.length;
        int[] parents = new int[n + 1];//存储每个节点的父节点
        Arrays.fill(parents, -1);
        int[] heigh = new int[n + 1];//存储根节点的深度
        for(int[] edge: edges){//遍历所有的边
            if(!t_Union(edge[0], edge[1], parents, heigh)){
                break;
            }
        }
        return ans;
    }
    private int find_Root(int root, int[] parents){//查找到根节点(祖先)
        while(parents[root] != -1){
            root = parents[root];
        }
        return root;
    }
    private boolean t_Union(int x, int y, int[] parents, int[] heigh){//合并
        int x_root = find_Root(x, parents);//如果根节点相同,则存在环,合并失败
        int y_root = find_Root(y, parents);
        if(x_root == y_root){
            ans[0] = x;
            ans[1] = y;
            return false;
        }else if(heigh[x_root] > heigh[y_root]){//将深度小的合并到深度大的根节点上
            parents[y_root] = x_root;
        }else if(heigh[x_root] < heigh[y_root]){
            parents[x_root] = y_root;
        }else{
            parents[y_root] = x_root;
            heigh[x_root]++;
        }
        return true;
    }
}

C++

class Solution {
public:
    vector<int> ans;
    vector<int> findRedundantConnection(vector<vector<int>>& edges) {
        int n = edges.size();
        vector<int> parents(n + 1, -1);//存储每个节点的父节点
        vector<int> heigh(n + 1, 0);//存储根节点的深度
        for(auto edge : edges){//遍历所有的边
            if(!t_Union(edge[0], edge[1], parents, heigh)) break;
        }
        return ans;
    }
    int find_Root(int root, vector<int>& parents){//查找到根节点(祖先)
        while(parents[root] != -1){
            root = parents[root];
        }
        return root;
    }
    bool t_Union(int x, int y, vector<int>& parents, vector<int>& heigh){//合并
        int x_root = find_Root(x, parents);
        int y_root = find_Root(y, parents);
        if(x_root == y_root){//如果根节点相同,则存在环,合并失败
            ans.push_back(x);
            ans.push_back(y);
            return false;
        }else if(heigh[x_root] > heigh[y_root]){//将深度小的合并到深度大的根节点上
            parents[y_root] = x_root;
        }else if(heigh[x_root] < heigh[y_root]){
            parents[x_root] = y_root;
        }else{
            parents[y_root] = x_root;
            heigh[x_root]++;
        }
        return true;
    }
};

🚀 运行结果:

在这里插入图片描述

🕔 复杂度分析:

  • 时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn),其中 n 是图中的节点个数,需要遍历图中的 n 条边,对于每条边,需要对两个节点查找祖先,如果两个节点的祖先不同则需要进行合并,需要进行 2 次查找和最多 1 次合并。一共需要进行 2n 次查找和最多 n 次合并,因此总时间复杂度是 O ( 2 n l o g n ) O(2nlogn) O(2nlogn) = O ( n l o g n ) O(nlogn) O(nlogn)
  • 空间复杂度 O ( n ) O(n) O(n),其中 n 是图中的节点个数,使用数组 parents 记录每个节点的祖先。

题目来源:力扣。

放弃一件事很容易,每天能坚持一件事一定很酷,一起每日一题吧!
关注我 leetCode专栏,每日更新!

注: 如有不足,欢迎指正!

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

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

相关文章

基于 EKS Fargate 搭建微服务性能分析系统

背景 近期 Amazon Fargate 在中国区正式落地&#xff0c;因 Fargate 使用 Serverless 架构&#xff0c;更加适合对性能要求不敏感的服务使用&#xff0c;Pyroscope 是一款基于 Golang 开发的应用程序性能分析工具&#xff0c;Pyroscope 的服务端为无状态服务且性能要求不敏感&…

Java阶段二Day14

Java阶段二Day14 文章目录 Java阶段二Day14复习前日知识点SpringFramework版本SpringFramework核心SpringFramework创建工程SpringFramework相关概念bean对象的创建过程xml配置文件中的标签 基于XML管理bean对象类型属性的注入数组类型属性注入集合类型属性注入p命名空间引入外…

ConMask: Open-World Knowledge Graph Completion

目录 Abstract Introduction Model Relationship-Dependent Content Masking Target Fusion Loss Function [1711.03438] Open-World Knowledge Graph Completion (arxiv.org) Abstract 引入一个名为ConMask的开放世界KGC模型&#xff0c;该模型学习实体名称和部分文本…

数据结构与算法基础-学习-23-图之邻接矩阵与邻接表

目录 一、定义和术语 二、存储结构 1、邻接矩阵 1.1、邻接矩阵优点 1.2、邻接矩阵缺点 2、邻接表 3、邻接矩阵和邻接表的区别和用途 3.1、区别 3.2、用途 三、宏定义 四、结构体定义 1、邻接矩阵 2、邻接表 3、网数据类型&#xff08;造测试数据&#xff09; 五…

如何使用TRIZ理论来分析问题和解决问题?

文章目录 TRIZ基础现代TRIZ步骤 TRIZ基础 现代TRIZ 经典的TRIZ方法对专利进行分析,认为专利分为两个部分,一部分是需要解决的问题,一部分是解决问题的解决方案.首先是问题的分析,确定是否是初始问题,比如工具功能分析/特性传递等工具. 步骤 问题识别 主要是识别出初始问题;…

MATLAB实现建筑热平衡模型建立及节能温控方案

全球大约1/3的能源消耗于建筑。在能源紧张的今天&#xff0c;如何减少建筑的能源浪费是一个值得研究的课题。 本文在综合国内外建筑能耗模拟方法的基础上&#xff0c;采用热平衡法&#xff0c;针对一小型建筑建立了热特性仿真模型&#xff0c;选用武汉地区的气象数据&#xff…

JAVA11新特性

JAVA11新特性 概述 2018年9月26日,Oracle官方发布JAVA11.这是JAVA大版本周期变化后的第一个长期支持版本,非常值得关注.最新发布的JAVA11将带来ZGC HttpClient等重要特性,一共17个需要我们关注的JEP,参考文档http://openjdk.java.net/projects/jdk/11/ 181:基于嵌套的访问控制…

云计算适合大专生学吗?

云计算适合大专生学吗&#xff1f; 对于大专毕业生来说&#xff0c;云计算的确是一个不错的选择&#xff0c;因为云计算技术应用专业&#xff0c;主要就是专科院校在办学。不管你是计算机相关专业的&#xff0c;还是零基础想学习都是可以的&#xff1b;原因就在于云计算这门专业…

七款非常好用的 ChatGPT 开源插件

推荐7款很好用的 ChatGPT 开源插件 1. ChatGPT ProBot 这是一个基于chatGPT实现的Github机器人&#xff0c;可以让chatGPT帮你审核代码、重构代码&#xff0c;还可以在Github页面上和它进行聊天&#xff0c;咨询问题。 仓库地址: github.com/oceanlvr/Ch… 2.chatgpt-api 这…

如何在本地部署运行ChatGLMS-6B

在本篇技术博客中&#xff0c;将展示如何在本地获取运行代码和模型&#xff0c;并配置环境以及 Web GUI&#xff0c;最后通过 Gradio 的网页版 Demo 进行聊天。 官方介绍 ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型&#xff0c;基于 General Language Model (GLM)…

图应用替换算法

文章目录 LRUSHiPBeladys MIN replacement(T-OPT)图应用基本知识CSR和CSCT-OPT替换算法使用 P-OPTRereference MatrixModified Rereference Matrix LRU 过于简单不做具体介绍 SHiP SHiP全称Signature-base Hit Predctor算法&#xff0c;其主打的是基于Signature(签名)进行Pr…

flutter学习之旅 -有状态的组件(StatefulWidget)

文章目录 StatefulWidget格式实现num增加finalfinal定义数组 我们重建一个项目 flutter create 项目名我们会看到 在Flutter中自定义组件其实就是一个类&#xff0c;这个类需要继承StatelessWidget/StatefulWidget StatelessWidget是无状态组件&#xff0c;状态不可改变的widg…

点成分享丨细胞培养三步骤——复苏、传代、冻存

细胞培养是指在体外模拟生物体内环境&#xff08;无菌、适宜温度、酸碱度和一定营养条件等&#xff09;&#xff0c;使之生存、生长、繁殖并维持主要结构和功能的一种方法。 细胞培养也叫细胞克隆技术&#xff0c;是细胞生物学研究方法中重要和常用技术&#xff0c;通过细胞培…

k近邻法学习

k近邻法&#xff08;k-nearest neighbor, k-NN)是一种基本分类与回归方法&#xff08;下面只写分类的&#xff09; knn的输入为实例的特征向量&#xff0c;对应于特征空间的店&#xff1b; 输出为实例的类别。 knn假设给定的训练数据集&#xff0c;其中的实力类别已定&#xf…

使用vscode进行python的单元测试,提高开发效率

背景知识 单元测试在我们的开发过程中非常有必要&#xff0c;它可以验证实现的一个函数是否达到预期。以前在学校写代码时&#xff0c;都是怼一堆代码&#xff0c;然后直接运行&#xff0c;如果报错再一步步调试&#xff0c;这样大部分时间都浪费在调试工作上。工作后发现大家…

【c/c++】curl编译(CMake方式)

一、curl下载 下载地址&#xff1a;curl - Download 进入下载页面&#xff0c;选择Old Releases。 二、CMake下载 这玩意居然有官网&#xff0c;刷新了我的认知&#xff0c;省事啊。 Download | CMake 三、CMake生成VS项目 1、点击【Browse Source ...】&#xff0c;先选择…

蓝牙耳机哪个品牌最好?数码博主整理2023超高性价比蓝牙耳机推荐

近来收到很多私信不知道蓝牙耳机哪个品牌最好&#xff0c;希望我能进行一期蓝牙耳机推荐&#xff0c;考虑到大家的预算不高&#xff0c;我特意花费时间测评了当下主流品牌的热销平价蓝牙耳机&#xff0c;最终整理成了这份超高性价比蓝牙耳机推荐&#xff0c;感兴趣的朋友们可以…

ASN.1-PKCS10

ASN1采用一个个的数据块来描述整个数据结构&#xff0c;每个数据块都有四个部分组成&#xff1a; 1、数据块数据类型标识&#xff08;一个字节&#xff09; 数据类型包括简单类型和结构类型。 简单类型是不能再分解类型&#xff0c;如整型(INTERGER)、比特串(BIT STRING)、字…

【Unity】搭建Jenkins打包工作流,远程打热更、构建App

Jenkins是团队协作项目打包常用的工作流&#xff0c;不多做介绍。 Jenkins的部署Unity打包环境还是非常简单的&#xff1a; 工作流程如下&#xff1a; 1. 在Jenkins中添加打包配置参数(如: 版本号, 目标平台等), 参数将以UI的形式显示在Jenkins Web界面以便打包前填写参数&a…

机器人抓取检测——Dex-Net

如今&#xff0c;在各种期刊顶会都能看到平面抓取检测的论文&#xff0c;他们声称能应对多物体堆叠场景&#xff0c;然而实际效果都不尽人意&#xff0c;我认为主要原因有如下几点&#xff1a; 缺乏多物体堆叠场景的抓取数据集。现在最常用的Cornell Grasp Dataset, Jacquard数…