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

并查集的典型应用:统计省份数量

题目来源:https://leetcode.com/problems/number-of-provinces/description/

有 n 个城市,其中一些彼此直接相连,另一些则没有直接相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。

省份定义为一组直接或间接相连的城市,且这组城市之外不包含其他与该组内城市相连的城市。

给你一个 n x n 矩阵 isConnected,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。

请你返回矩阵中省份的总数量。

【解】

这道题是 LeetCode 547,本质上就是求无向图的连通分量个数,与并查集的经典用法完全吻合。

解题思路

  1. 问题转化

    • n个城市,isConnected[i][j] = 1表示城市ij直接相连。
    • 省份 = 连通分量。求图中连通分量的总数。
  2. 并查集建模

    • 初始时,每个城市自成一个省份,省份数量count = n
    • 遍历矩阵的上三角部分(i < j),若isConnected[i][j] == 1,说明两个城市直接相连,应属于同一个省份。
    • 调用union(i, j),若合并成功(之前不在同一集合),则当前省份数量减1
    • 最终count就是省份的总数。
  3. 复杂度分析

    • 时间:O(n^2 * α(n))O(n^2),其中α(n)是反阿克曼函数,可以视为常数。
    • 空间:O(n),用于存储parentrank数组。

代码实现(Python)

classUnionFind:def__init__(self,n):self.parent=list(range(n))self.rank=[0]*n self.count=n# 连通分量个数deffind(self,x):ifself.parent[x]!=x:self.parent[x]=self.find(self.parent[x])# 路径压缩returnself.parent[x]defunion(self,x,y):rootX=self.find(x)rootY=self.find(y)ifrootX==rootY:returnFalse# 已在同一集合,合并失败# 按秩合并ifself.rank[rootX]<self.rank[rootY]:self.parent[rootX]=rootYelifself.rank[rootX]>self.rank[rootY]:self.parent[rootY]=rootXelse:self.parent[rootY]=rootX self.rank[rootX]+=1self.count-=1# 成功合并,连通分量减1returnTrueclassSolution:deffindCircleNum(self,isConnected:List[List[int]])->int:n=len(isConnected)uf=UnionFind(n)foriinrange(n):forjinrange(i+1,n):# 只需遍历上三角ifisConnected[i][j]==1:uf.union(i,j)returnuf.count

解题步骤解析

  • 第 3 行:并查集类中额外维护count,表示当前连通分量个数,初始化为n
  • 第 11~17 行find采用递归写法,同时进行路径压缩,使得后续查找近似常数时间。
  • 第 19~31 行union方法在成功合并两个不同集合时,将count减 1,其余逻辑与标准按秩合并一致。
  • 第 36~38 行:双重循环只遍历i < j的部分,避免重复和自环。若两城市直接相连,则尝试合并。
  • 第 39 行:最后直接返回uf.count即为省份总数。

以下是使用 C 语言实现的并查集解法,完全按照考研及算法题的标准写法编写,包含路径压缩按秩合并优化。

#include<stdlib.h>// 查找操作:路径压缩intfind(int*parent,intx){if(parent[x]!=x)parent[x]=find(parent,parent[x]);// 递归压缩路径returnparent[x];}// 合并操作:按秩合并,并通过指针修改连通分量计数voidunionSet(int*parent,int*rank,int*count,intx,inty){introotX=find(parent,x);introotY=find(parent,y);if(rootX==rootY)return;// 已在同一集合,不合并// 将较矮的树挂到较高的树下if(rank[rootX]<rank[rootY]){parent[rootX]=rootY;}elseif(rank[rootX]>rank[rootY]){parent[rootY]=rootX;}else{parent[rootY]=rootX;rank[rootX]++;// 高度相等时树高增1}(*count)--;// 连通分量数减1}intfindCircleNum(int**isConnected,intisConnectedSize,int*isConnectedColSize){intn=isConnectedSize;// 动态分配并查集所需数组int*parent=(int*)malloc(n*sizeof(int));int*rank=(int*)malloc(n*sizeof(int));// 初始化:每个城市自成一个集合for(inti=0;i<n;i++){parent[i]=i;rank[i]=0;}intprovinces=n;// 初始省份数量等于城市数量// 遍历矩阵的上三角部分,避免重复for(inti=0;i<n;i++){for(intj=i+1;j<n;j++){if(isConnected[i][j]==1){unionSet(parent,rank,&provinces,i,j);}}}intresult=provinces;// 释放内存free(parent);free(rank);returnresult;}

说明

  1. 函数签名
    严格按照 LeetCode 547 题的 C 接口要求:
    int findCircleNum(int** isConnected, int isConnectedSize, int* isConnectedColSize)
    其中isConnectedSize为城市数量nisConnectedColSize为每行的列数数组(可不用)。

  2. 并查集核心操作

    • find:递归实现,路径压缩使树扁平化,均摊近乎O(1)
    • unionSet按秩合并(用rank记录树高上界),避免树无故增高;合并成功时将省份计数provinces减 1。
  3. 复杂度分析

    • 时间:O(n^2 · α(n))O(n^2),其中α(n)为反阿克曼函数,可视为常数。
    • 空间:O(n),仅需两个长度为n的数组。
http://www.jsqmd.com/news/1079832/

相关文章:

  • 便捷在线公证办理指南,让生活更简单!
  • 移动Linux开发调试利器:JTAG与i.MX处理器实战指南
  • Roblox帧率解锁终极指南:突破60FPS限制的完整教程
  • Qt 5.15.2 + Android 开发环境配置指南
  • KMP与AC自动机:让字符串匹配“跳着走”
  • 跨语言项目开发:Cursor 联动 Claude Code 搞定 Java+Python 混合工程难题
  • 图片去水印工具推荐:个人收藏学习向免费在线与电脑手机方案,安全无广告
  • 实测横评:图片去水印工具有哪些?免费在线网站和电脑手机端真实体验全记录
  • 奇门WMS-A与金蝶云星空的数据集成价值分析
  • “太卷了!”2026技术校招笔试现场崩溃实录,看完你就不焦虑了
  • AI生产力杠杆使用说明书:嵌入工作流的实战方法论
  • 小程序毕设选题推荐:基于微信小程序的游记发布与旅游足迹展示系统设计与实现 SpringBoot 框架下旅游动态分享与游迹管理系统设计与实现【附源码、mysql、文档、调试+代码讲解+全bao等】
  • vulnhub靶场From SQL injection to Shell
  • 工业高危环境防爆监控选型技术指南|广东化工 / 矿用场景设备合规与落地方案分析
  • IACheck AI报告文档审核|自动识别合规要素漏洞,杜绝管材压扁试验报告签字签章缺失问题
  • 【计算机毕业设计案例】基于 SpringBoot + 小程序的儿童预防接种综合管理系统设计与实现(程序+文档+讲解+定制)
  • 【毕业设计】基于 SpringBoot 的消防知识在线答题与竞赛系统设计与实现 轻量化消防安全知识闯关竞赛小程序设计与实现(源码+文档+远程调试,全bao定制等)
  • 全光校园网络等保合规建设方案
  • sqlserver设置最大占用内存
  • 链路追踪:SkyWalking, Zipkin 入门
  • 华为交换机风扇异常处理
  • Playwright与pytest-playwright:从自动化库到测试框架的深度解析
  • 告别大学生笔记内耗!实测AI语音转写工具,解锁高效学习方式
  • 计算机小程序毕设实战-基于 SpringBoot 的移动端消防知识答题竞赛平台设计与实现 面向校园普及的消防安全知识竞赛小程序设计与实现【完整源码+LW+部署说明+演示视频,全bao一条龙等】
  • 别再加个“聊天框”自欺欺人了!2026企业AI大脑生死战:大模型撕掉伪智能面具的终极对决
  • 抢演唱会门票稳了|鸿蒙6.1+抢票引擎,华为nova16系列让我抢票率飙升
  • 免费图片去水印工具实操步骤:从网页到本地再到小程序,完整去水印流程
  • 企业AI品牌测评中的样本量与统计可靠性分析
  • 合同统计分析:让数据参与经营判断
  • 鸿蒙 EventBus 与 Message 通信机制详解