尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

并查集算法解析与卡码网107题实战

发布时间:2026/9/14 9:50:37

资讯中心
01
ARTICLE

并查集算法解析与卡码网107题实战

并查集算法解析与卡码网107题实战
1. 并查集算法基础与应用场景1.1 什么是并查集并查集Disjoint Set UnionDSU是一种处理不相交集合合并及查询问题的数据结构。它主要支持两种操作Find查找元素所属集合Union合并两个集合这种数据结构特别适合处理动态连通性问题比如社交网络中的好友关系、计算机网络中的连接状态等。在算法竞赛和实际工程中并查集因其高效的特性接近O(1)的时间复杂度而被广泛应用。1.2 并查集的核心操作并查集的核心在于两个优化操作路径压缩Path Compression在Find操作时将查找路径上的所有节点直接指向根节点使树结构更加扁平按秩合并Union by Rank在Union操作时将较小的树合并到较大的树下保持树的平衡这两个优化使得并查集的操作时间复杂度接近常数级别在实际应用中表现优异。1.3 并查集在图论中的应用在图论问题中并查集常用来判断图中两个节点是否连通寻找图中的连通分量检测图中是否存在环特别是在处理无向图的连通性问题时并查集往往比DFS/BFS更高效。卡码网107题寻找存在的路线就是一个典型的应用场景。2. 卡码网107题解析2.1 题目描述与理解题目描述给定一个无向图判断两个指定节点之间是否存在路径。输入格式第一行节点数n和边数m接下来m行每行两个整数表示一条边连接的两个节点最后一行两个整数表示要查询的节点输出要求如果存在路径输出YES否则输出NO2.2 并查集解法思路使用并查集解决此问题的基本思路初始化每个节点都是自己的父节点处理边对于每条边合并两个端点所在的集合查询检查两个查询节点是否属于同一集合这种方法的优势在于预处理后查询操作可以在近乎常数时间内完成。2.3 代码实现框架以下是基于Python的并查集实现框架class DSU: def __init__(self, n): self.parent [i for i in range(n1)] # 1-based索引 def find(self, x): if self.parent[x] ! x: self.parent[x] self.find(self.parent[x]) # 路径压缩 return self.parent[x] def union(self, x, y): x_root self.find(x) y_root self.find(y) if x_root ! y_root: self.parent[y_root] x_root def solve(): n, m map(int, input().split()) dsu DSU(n) for _ in range(m): u, v map(int, input().split()) dsu.union(u, v) a, b map(int, input().split()) print(YES if dsu.find(a) dsu.find(b) else NO)3. 并查集优化技巧3.1 按秩合并的实现按秩合并可以进一步优化并查集的性能。我们在每个节点记录其所在树的深度秩合并时总是将较小的树合并到较大的树下class DSU: def __init__(self, n): self.parent [i for i in range(n1)] self.rank [0]*(n1) # 初始化秩 def find(self, x): if self.parent[x] ! x: self.parent[x] self.find(self.parent[x]) return self.parent[x] def union(self, x, y): x_root self.find(x) y_root self.find(y) if x_root y_root: return # 按秩合并 if self.rank[x_root] self.rank[y_root]: self.parent[x_root] y_root else: self.parent[y_root] x_root if self.rank[x_root] self.rank[y_root]: self.rank[x_root] 13.2 路径压缩与按秩合并的结合同时使用路径压缩和按秩合并时按秩合并中的秩不再是实际树的高度而是一个上界估计。但这对算法的正确性没有影响仍然能保证良好的性能。注意在实际编码中按秩合并有时会被更简单的按大小合并替代即记录每个集合的大小而非秩也能达到类似的优化效果。4. 实际应用中的注意事项4.1 输入数据的处理在处理实际问题时需要注意节点编号是0-based还是1-based是否有重复边需要处理是否需要考虑自环边在卡码网107题中输入数据通常是1-based的且不需要特别处理重复边和自环边。4.2 边界条件检查常见的边界情况包括查询的两个节点相同图中只有一个节点图中没有边查询的节点超出范围良好的编程习惯应该总是先检查这些边界条件。4.3 性能优化技巧对于大规模数据使用更快的输入方法如sys.stdin避免不必要的对象创建在知道最大节点数的情况下使用固定大小的数组而非动态结构5. 并查集的变种与应用扩展5.1 带权并查集带权并查集在维护连通性的同时还能维护节点之间的关系。常见应用包括食物链问题亲戚关系计算等式方程的可满足性实现时需要额外维护一个权重数组并在find和union操作时更新权重。5.2 动态连通性问题并查集特别适合处理动态连通性问题即边会动态添加的场景。相比DFS/BFS每次查询都需要重新遍历并查集可以在O(α(n))时间内处理每个查询。5.3 其他图论问题并查集还可以用于最小生成树算法Kruskal算法离线LCA问题双连通分量检测6. 常见错误与调试技巧6.1 初始化错误常见错误包括忘记初始化父数组数组大小设置不正确少1或多10-based和1-based混淆调试时可以打印出父数组检查初始化是否正确。6.2 路径压缩实现错误错误的路径压缩实现可能导致无限递归或压缩不彻底。正确的实现应该像这样def find(self, x): if self.parent[x] ! x: self.parent[x] self.find(self.parent[x]) # 递归压缩 return self.parent[x]而非# 错误的实现没有真正压缩路径 def find(self, x): while self.parent[x] ! x: x self.parent[x] return x6.3 按秩合并的误区按秩合并中常见的错误忘记初始化秩数组合并时比较的是节点本身而非根节点秩更新逻辑错误正确的比较应该总是比较根节点的秩。7. 算法复杂度分析7.1 时间复杂度使用路径压缩和按秩合并的并查集每个操作的平均时间复杂度是O(α(n))其中α是反阿克曼函数增长极其缓慢可以认为是常数时间。对于卡码网107题初始化O(n)处理m条边O(mα(n))查询O(α(n)) 总体复杂度O(n mα(n))7.2 空间复杂度并查集需要存储父数组和秩数组空间复杂度是O(n)。7.3 与其他算法的比较相比DFS/BFS的O(nm)查询复杂度并查集在需要多次查询时优势明显。但在只需要单次查询或需要知道具体路径时DFS/BFS可能更合适。8. 实际编码建议8.1 代码模板化建议将并查集实现为可重用的类或结构体方便在不同问题中快速应用。一个完整的Python模板import sys from sys import stdin class DSU: def __init__(self, n): self.parent list(range(n1)) self.rank [0]*(n1) def find(self, x): if self.parent[x] ! x: self.parent[x] self.find(self.parent[x]) return self.parent[x] def union(self, x, y): xr, yr self.find(x), self.find(y) if xr yr: return if self.rank[xr] self.rank[yr]: self.parent[xr] yr else: self.parent[yr] xr if self.rank[xr] self.rank[yr]: self.rank[xr] 1 def main(): input sys.stdin.read().split() ptr 0 n, m int(input[ptr]), int(input[ptr1]) ptr 2 dsu DSU(n) for _ in range(m): u, v int(input[ptr]), int(input[ptr1]) ptr 2 dsu.union(u, v) a, b int(input[ptr]), int(input[ptr1]) print(YES if dsu.find(a) dsu.find(b) else NO) if __name__ __main__: main()8.2 输入输出优化对于大规模数据使用快速的输入方法可以显著提升性能import sys input sys.stdin.read().split() ptr 0 n, m int(input[ptr]), int(input[ptr1]) ptr 28.3 测试用例设计设计测试用例时应考虑普通连通图不连通图单节点图完全图链状图星型图例如测试输入1 4 2 1 2 3 4 1 3 预期输出NO 测试输入2 4 4 1 2 2 3 3 4 1 4 1 4 预期输出YES9. 并查集相关题目推荐9.1 基础练习题卡码网107 - 寻找存在的路线本题LeetCode 547 - 省份数量LeetCode 684 - 冗余连接LeetCode 200 - 岛屿数量也可用DFS/BFS9.2 进阶挑战题LeetCode 128 - 最长连续序列LeetCode 399 - 除法求值带权并查集LeetCode 765 - 情侣牵手LeetCode 952 - 按公因数计算最大组件大小9.3 竞赛经典题Codeforces 25D - Roads not only in BerlandCodeforces 1213G - Path QueriesAtCoder ABC177D - FriendsSPOJ DISUBSTR - Distinct Substrings需要结合其他算法10. 学习资源与延伸阅读10.1 推荐书籍《算法导论》- 第21章 用于不相交集合的数据结构《算法竞赛入门经典》- 第11章 图论模型与算法《算法竞赛进阶指南》- 0x41 并查集10.2 在线资源Visualgo.net 上的并查集可视化Topcoder 并查集教程GeeksforGeeks 并查集专题10.3 学术论文对于想深入研究的读者可以阅读Tarjan的原始论文《Efficiency of a Good But Not Linear Set Union Algorithm》《Worst-case Analysis of Set Union Algorithms》11. 个人实战经验分享在实际使用并查集解决问题时有几个经验值得分享调试技巧当程序出现问题时打印出父数组和秩数组通常能快速定位问题。特别是在处理复杂问题时中间状态的检查非常重要。模板定制根据不同的比赛平台如LeetCode、Codeforces调整输入输出方式。有些平台对输入速度要求高需要更高效的读取方法。空间优化在知道节点范围的情况下使用数组而非字典实现并查集可以显著提高性能。例如当节点编号是连续的整数时。问题转化很多看似不相关的问题可以转化为连通性问题。例如处理网格问题时可以将每个格子视为节点相邻关系视为边。性能测试对于大规模数据如n1e5在本地生成随机测试数据验证算法性能是很好的习惯。这可以避免在比赛中遇到超时问题。并查集是我最喜欢的算法之一它的简洁性和高效性令人惊叹。掌握好这个数据结构能在解决许多问题时事半功倍。建议初学者从基础题目开始逐步挑战更复杂的问题体会并查集的精妙之处。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。