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

代码随想录训练营 Day56打卡 图论part06 108. 冗余连接 109. 冗余连接II

代码随想录训练营 Day56打卡 图论part06

一、卡码108. 冗余连接

题目描述
有一个图,它是一棵树,他是拥有 n 个节点(节点编号1到n)和 n - 1 条边的连通无环无向图(其实就是一个线形图),如图:

现在在这棵树上的基础上,添加一条边(依然是n个节点,但有n条边),使这个图变成了有环图,如图:

先请你找出冗余边,删除后,使该图可以重新变成一棵树。
输入描述
第一行包含一个整数 N,表示图的节点个数和边的个数。
后续 N 行,每行包含两个整数 s 和 t,表示图中 s 和 t 之间有一条边。
输出描述
输出一条可以删除的边。如果有多个答案,请删除标准输入中最后出现的那条边。
输入示例
3
1 2
2 3
1 3
输出示例
1 3
提示信息

图中的 1 2,2 3,1 3 等三条边在删除后都能使原图变为一棵合法的树。但是 1 3 由于是标准输出里最后出现的那条边,所以输出结果为 1 3

  1. 树的性质:一棵树有 n 个节点和 n-1 条边,是一个连通且无环的图。如果给一棵树多加一条边,那么它就会形成一个环。
  2. 寻找冗余边:使用并查集来判断每次加边时,是否会形成环。如果发现某一条边连接的两个节点已经属于同一个连通分量(即它们已经连通),说明这条边是冗余的,即它会导致环的出现。
  3. 返回结果:根据题目要求,返回输入中最后出现的那条冗余边。

代码实现

class Solution:def findRedundantConnection(self, edges: list[list[int]]) -> list[int]:n = len(edges)  # 由于题目给定 n 条边,所以有 n 个节点parent = list(range(n + 1))  # 初始化并查集,每个节点的父节点初始化为它自己# 并查集的 find 函数,使用路径压缩优化def find(index: int) -> int:if parent[index] != index:  # 如果当前节点的父节点不是自己parent[index] = find(parent[index])  # 递归找到根节点,并将路径上的所有节点直接指向根节点return parent[index]  # 返回根节点# 并查集的 union 函数,合并两个节点所在的集合def union(index1: int, index2: int):parent[find(index1)] = find(index2)  # 将 index1 的根节点连接到 index2 的根节点# 遍历所有边,执行并查集的合并操作for node1, node2 in edges:if find(node1) != find(node2):  # 如果 node1 和 node2 不在同一个集合中union(node1, node2)  # 合并它们的集合else:return [node1, node2]  # 如果 node1 和 node2 已经在同一个集合中,说明这条边是冗余边return []  # 题目保证输入合法,所以不会执行到这里

卡码题目链接
题目文章讲解

二、卡码109. 冗余连接II

题目描述
有一种有向树,该树只有一个根节点,所有其他节点都是该根节点的后继。该树除了根节点之外的每一个节点都有且只有一个父节点,而根节点没有父节点。有向树拥有 n 个节点和 n - 1 条边。如图:

现在有一个有向图,有向图是在有向树中的两个没有直接链接的节点中间添加一条有向边。如图:

输入一个有向图,该图由一个有着 n 个节点(节点编号 从 1 到 n),n 条边,请返回一条可以删除的边,使得删除该条边之后该有向图可以被当作一颗有向树。
输入描述
第一行输入一个整数 N,表示有向图中节点和边的个数。
后续 N 行,每行输入两个整数 s 和 t,代表这是 s 节点连接并指向 t 节点的单向边
输出描述
输出一条可以删除的边,若有多条边可以删除,请输出标准输入中最后出现的一条边。
输入示例
3
1 2
1 3
2 3
输出示例
2 3
提示信息

在删除 2 3 后有向图可以变为一棵合法的有向树,所以输出 2 3

这道题的目的是在有向图中找到一条冗余边,该冗余边可以是多余的边或导致图中形成环路的边。具体解决思路是通过并查集和父节点数组相结合,来处理节点的父节点冲突以及环路检测问题。

题解思路

  1. 分析图的性质:
    树的性质:一棵树有 n 个节点和 n-1 条边,是一个无环的连通图。
    有向图的情况:给定的图有 n 个节点和 n 条边,多了一条附加的边,因此图可能会出现两种情况:
        · 有一个节点有两个父节点,即一个节点被指向两次。
        · 有环路,即一个节点可以通过有向边回到自己。
  2. 解决方法:
    记录每个节点的父节点:使用数组 parent 来记录每个节点的父节点。如果发现某个节点有两个父节点,说明存在冲突(conflict)。
    使用并查集检测环路:通过并查集(Union-Find)来检测是否有环路(cycle)。如果在合并时发现两个节点已经属于同一集合,说明这条边会导致环路。
    根据冲突和环路的情况返回结果
    如果有冲突但没有环路,那么冲突的边就是冗余边。
    如果同时有冲突和环路,优先返回与环路相关的边。
    如果没有冲突但有环路,返回环路中的最后一条边。

举个栗子

为什么优先删除与环路相关的边?
如果有冲突但没有环路,那么说明其中一条边只是使某个节点有两个父节点,此时直接删除指向该节点的后出现的那条边即可。

但如果同时存在父节点冲突和环路,此时导致问题的根源是环路,因为冗余边不仅让一个节点有两个父节点,还让整个图形成了一个环。优先删除与环路相关的边可以确保解决问题。

假设输入的图如下:

edges = [[1, 2], [2, 3], [3, 4], [4, 2], [1, 5]]

图的结构:

   1/ \2 - 5|3|4|2  <-- 环路
  • 父节点冲突:边 [4, 2] 让节点 2 有两个父节点(分别是 1 和 4)。
  • 环路:2 → 3 → 4 → 2 形成一个环。

此时,我们要优先删除形成环的那条边,即 [4, 2],这样可以确保我们既消除了环路,又让图成为一棵树。

因此,在有冲突和环路的情况下,删除环路中的冗余边更能有效解决问题,避免冗余的边继续影响树的结构。

冲突是因为一个节点有多个父节点。
环路是因为多余的边使得整个图不再是树。

代码实现

class UnionFind:def __init__(self, n):# 初始化并查集,每个节点的祖先初始化为自己self.ancestor = list(range(n))# 合并两个节点所在的集合def union(self, index1: int, index2: int):# 找到两个节点的根,并将其中一个根指向另一个根self.ancestor[self.find(index1)] = self.find(index2)# 查找节点的根,同时进行路径压缩def find(self, index: int) -> int:if self.ancestor[index] != index:# 路径压缩,将当前节点的父节点直接指向根self.ancestor[index] = self.find(self.ancestor[index])return self.ancestor[index]class Solution:def findRedundantDirectedConnection(self, edges: list[list[int]]) -> list[int]:n = len(edges)  # 图的节点数uf = UnionFind(n + 1)  # 初始化并查集parent = list(range(n + 1))  # 每个节点的父节点初始化为自己conflict = -1  # 记录冲突边的索引cycle = -1  # 记录环路边的索引# 遍历所有边for i, (node1, node2) in enumerate(edges):if parent[node2] != node2:# 如果 node2 已经有父节点,说明冲突发生,记录这条边conflict = ielse:# 否则,更新 node2 的父节点为 node1parent[node2] = node1# 判断是否形成环路if uf.find(node1) == uf.find(node2):# 如果 node1 和 node2 已经属于同一个集合,说明形成了环路cycle = ielse:# 如果没有形成环路,将 node1 和 node2 合并到同一个集合uf.union(node1, node2)# 如果没有冲突边,返回导致环路的那条边if conflict < 0:return [edges[cycle][0], edges[cycle][1]]else:# 处理冲突边conflictEdge = edges[conflict]if cycle >= 0:# 如果有环路,返回与环路相关的边return [parent[conflictEdge[1]], conflictEdge[1]]else:# 如果没有环路,直接返回冲突边return [conflictEdge[0], conflictEdge[1]]

时间复杂度

  • 查找和合并的均摊时间复杂度为 O(α(n)),其中 α(n) 是反阿克曼函数,近似为常数。
  • 遍历所有边的时间复杂度为 O(n)。
  • 总体复杂度接近 O(n)。

卡码题目链接
题目文章讲解

相关文章:

代码随想录训练营 Day56打卡 图论part06 108. 冗余连接 109. 冗余连接II

代码随想录训练营 Day56打卡 图论part06 一、卡码108. 冗余连接 题目描述 有一个图&#xff0c;它是一棵树&#xff0c;他是拥有 n 个节点&#xff08;节点编号1到n&#xff09;和 n - 1 条边的连通无环无向图&#xff08;其实就是一个线形图&#xff09;&#xff0c;如图&…...

QT天气预报

json 理论 什么是JSON? 规则 被大括号包括的是JSON对象,被中括号包括的是JSON数组. JSON数组JSON对象 实验 构建JSON 用代码实现如下json内容: //构建JSON void WirteJson() {QJsonObject rootObject;//1.插入name字段rootObject.insert("name","china&quo…...

JavaWeb中处理 Web 请求的方式总结

文章目录 JavaWeb中处理 Web 请求的方式总结1. 原始的 Servlet 方式1.1. 环境搭建**创建 Maven 或 Gradle 项目**&#xff1a;**添加 Servlet 依赖**&#xff1a;**创建 Servlet 类**&#xff1a;**配置项目**&#xff1a;**配置 Tomcat**&#xff1a; 1.2. 路由机制1.3. 示例代…...

React的事件与原生事件的执行顺序?

react自身实现了一套自己的事件机制&#xff0c;包括事件注册、事件的合成、事件冒泡、事件派发等&#xff0c;虽然和原生的是两码事&#xff0c;但也是基于浏览器的事件机制下完成的。 react 的所有事件并没有绑定到具体的dom节点上而是绑定在了document 上&#xff0c;然后由…...

【Java】Runtime与Properties获取系统信息

Java系列文章目录 补充内容 Windows通过SSH连接Linux 第一章 Linux基本命令的学习与Linux历史 文章目录 Java系列文章目录一、前言二、学习内容&#xff1a;三、问题描述四、解决方案&#xff1a;4.1 代码4.2 运行结果 五、总结&#xff1a; 一、前言 这些都被淘汰比较少用了…...

基于SpringBoot的社团管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 基于JavaSpringBootVueMySQL的社团管理系统【附源码文档】、…...

UE5.3_跟一个插件—Socket.IO Client

网上看到这个插件,挺好! 项目目前也没有忙到不可开交,索性跟着测一下吧: 商城可见,售价72.61人民币! 但是,git上有仓库哦,免费!! 跟着链接先准备起来: Documentation: GitHub - getnamo/SocketIOClient-Unreal: Socket.IO client plugin for the Unreal Engin…...

鸿蒙轻内核A核源码分析系列七 进程管理 (1)

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 轻内核A核源码分析系列一 数据结构-双向循环链表 轻内核A核源码分析系列二 数据结构-位图操作 轻内核A核源码分析系列三 物理内存&#xff08;1&#xff0…...

qt QGraphicsScene场景坐标和场景内GraphicsItem局部坐标的相互转换

为了更清晰地解释场景坐标与局部坐标之间的转换过程&#xff0c;我们可以通过一个简单的实例来演示如何赋值场景坐标&#xff0c;并将其转换为图形项的局部坐标。 实例步骤 假设我们有一个场景 QGraphicsScene 和一个矩形图形项 QGraphicsRectItem&#xff0c;矩形的大小为 1…...

Windows与linux中docker的安装与使用

windos中安装使用docker 下载Docker_Desktop 安装包进入docker官网下载Docker_Desktop&#xff1a; https://www.docker.com/启用wsl 我们搜索“启用或关闭Windows功能”&#xff0c;打开后勾选适用于Linux的Windows 子系统 Docker_Desktop设置 出现Docker Engine stopp…...

some electronic products

纽扣电池 button cell 运动手环 sports wristband 智能手环 smart bracelet 皮卡丘夜灯 pikachu night lamp 数字显示充电器 Charger with a digital display 磁吸无线充 magnetic wireless charger 直流电机调速器 DC motor speed controller 继电器模块 relay module 锂离子电…...

刘润《关键跃升》读书笔记7

沟通&#xff1a; 想明⽩&#xff0c;说清楚&#xff0c;能接受 团队沟通的正确⽅式可以⽤9个字来概括&#xff1a;想明⽩&#xff0c;说清楚&#xff0c;能接受 &#xff08;⻅图4-1&#xff09;想明⽩ 有时经理跟⼈沟通&#xff0c;讲完之后却⽆奈地对员⼯说&#xff0c;你怎…...

带参宏定义

#define WM_EVENT_DECLARE_GROUP(group) extern wm_event_group_t const group 宏定义的结构&#xff1a; #define&#xff1a;这是C语言中的预处理指令&#xff0c;用来定义宏。宏的作用是替换代码中的特定部分&#xff0c;类似于全局的文本替换。这里定义的宏名称是 WM_EVE…...

java流

99. ByteArrayOutputStream转化为ByteArrayInputStream ByteArrayOutputStream baos xxx;i new ByteArrayInputStream(baos.toByteArray())100.将inputstream转换为byte[] https://blog.csdn.net/yogima/article/details/128500056 100.1 方式一 直接使用IOUtils byte[] …...

Java ArrayList扩容机制 (源码解读)

结论&#xff1a;初始长度为10&#xff0c;若所需长度小于1.5倍原长度&#xff0c;则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义 1&#xff1a;数组默认长度 2:这是一个共享的空数组实例&#xff0c;用于明确创建长度为0时的ArrayList &#xff…...

『功能项目』管理器基类【38】

我们打开上一篇37单例模式框架的项目&#xff0c; 本章要做的事情是编写管理器基类 首先创建脚本&#xff1a;ManagerBase.cs using UnityEngine; public abstract class ManagerBase : MonoBehaviour{public virtual void Init() { } } public class ManagerBase<T> : …...

Flex布局最后一行元素的对齐的解决方案

问题的产生 使用Flex布局&#xff0c;设置justify-content: space-between;让元素在主轴上两队对齐。 <div class"box"><div class"item">1</div><div class"item">2</div><div class"item">3&l…...

【ShuQiHere】上章:计算与计算机的基础概念

【ShuQiHere】✨ 在当今数字化社会&#xff0c;计算机已无处不在&#xff0c;从智能手机到人工智能应用&#xff0c;影响深远。然而&#xff0c;计算机并非一开始就如此强大。它经历了从手动工具、机械装置到电子计算机的演变。本章将回顾计算与算法的基本概念&#xff0c;探讨…...

前端框架有哪些?全面解析主流前端框架

一、React React 是由 Facebook 开发和维护的一个前端框架&#xff0c;它专注于构建用户界面。React 采用组件化的开发模式&#xff0c;允许开发者将用户界面拆分成多个可复用的组件。 主要特点 组件化: React 的核心是组件&#xff0c;它允许开发者将界面拆分成独立的、可复…...

4G MQTT网关在物联网应用中的优势-天拓四方

随着物联网&#xff08;IoT&#xff09;技术的飞速发展&#xff0c;各种设备和系统之间的互联互通变得日益重要。MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;作为一种轻量级的发布/订阅消息传输协议&#xff0c;因其高效、可靠、简单的特性&#xff0c;在…...

【网上商城项目结构】

文章目录 前言一、网站前台二、运营商后台三、商家管理后台四、系统架构五、数据库设计六、关键技术总结 前言 网上商城项目结构通常包括网站前台、运营商后台和商家管理后台三个子系统&#xff0c;以及多个功能模块&#xff0c;如门户、搜索、购物车、订单、秒杀、个人中心等…...

VMware-Ubuntu Server安装教程

整理了B站和考拉软件上的信息 VMware安装 1.下载完成后&#xff0c;鼠标右击【VMware Workstation Pro 17.5.1】压缩包&#xff0c;选择【解压至此】 2.打开解压后的文件夹&#xff0c;鼠标右击【VMware17.5】选择【以管理员身份运行】 3.点击【下一步】 4.勾选【我接受许可协…...

从hadoop平台下载文件到本地Windows

一、只能上传文件,不能下载 1、原因: 如果在Windows中没有配置hadoop的环境变量,用idea远程连接上hadoop平台之后,只能往hadoop上推送数据文件,并不能下载文件,因为下载时hadoop会检测本地有无hadoop环境配置,所以我们需要安装winutils,在windows本地模拟一个hadoop环…...

MySQL-CRUD入门2

文章目录 数据的查询(补充)条件查询关于SQL语句的执行顺序分页查询(LIMIT) 数据的修改数据修改基础知识 数据的查询(补充) 这一节接着写, 包括数据的查询(补充), 数据的更新, 数据的删除 条件查询 其实就是根据给定的一些条件, 然后过滤掉不符合实际情况的记录, 把符合条件的…...

高级java每日一道面试题-2024年9月06日-基础篇-Java中的PO、VO、BO、DO、DAO、DTO、POJO是什么意思?

如果有遗漏,评论区告诉我进行补充 面试官: Java中的PO、VO、BO、DO、DAO、DTO、POJO是什么意思? 我回答: PO持久化对象&#xff08;Persistent Object&#xff09; PO是持久化对象&#xff0c;用于表示数据库中的实体或表的映射 通常与数据库表的结构和字段对应 PO的属性对…...

MFC读取PC6408板卡输入信号实例

本程序基于前期我的博客文章《MFC用信号灯模拟工控机数字量输入信号实时采集实例&#xff08;源码下载》 1、在TheradDlg.h中相关代码 ... private:unsigned short nAddr; ... TheradDlg.cpp中相关代码 #include "pc60002k.h"BOOL CTheradDlg::OnInitDialog() { ..…...

@Async的使用说明

在 Spring Boot 中&#xff0c;Async 注解用于实现异步方法调用&#xff0c;允许方法在单独的线程中执行&#xff0c;从而避免阻塞主线程&#xff0c;提升应用的并发处理能力。 1. 基本用法 在 Spring Boot 中使用 Async 很简单&#xff0c;主要步骤如下&#xff1a; 步骤 1…...

经验笔记:SQL调优

SQL调优经验笔记 引言 SQL调优是确保数据库系统高效运行的重要环节。通过对查询语句、数据库配置、硬件资源等方面进行优化&#xff0c;可以显著提升数据库性能&#xff0c;进而增强应用程序的整体表现。以下是基于常见调优手段和实践经验整理的一份经验笔记。 1. 查询语句优…...

Selenium使用浏览器用户配置进行测试

本文主要介绍了如何在使用Selenium WebDriver进行自动化测试时&#xff0c;创建和使用自定义的Firefox配置文件。 什么是Firefox配置文件&#xff1f; Firefox会将用户的个人信息&#xff0c;如书签、密码和用户偏好设置存储在一个称为配置文件的文件集合中&#xff0c;这些文…...

virsh命令的使用

virsh 是一个用于管理虚拟机的命令行工具&#xff0c;它与 libvirt 服务配合使用&#xff0c;支持对虚拟机的创建、配置、启动、停止等操作。 1、列出虚拟机 列出正在运行的虚拟机&#xff1a; virsh list列出所有虚拟机&#xff08;包括未启动的&#xff09;&#xff1a; …...