[Leetcode 每日精选](本周主题-并查集) 547. 朋友圈
发布日期:2021-06-29 07:11:39
浏览次数:3
分类:技术文章
本文共 2778 字,大约阅读时间需要 9 分钟。
题目难度: 中等
今天继续来做并查集的问题, 这道题仍然比较基础, 而且也是个比较接近现实的问题了. 大家在我的公众号"每日精选算法题"中的聊天框中回复 并查集 就能看到该系列当前已经更新的文章了
大家有什么想法建议和反馈的话欢迎随时交流, 包括但不限于公众号聊天框/知乎私信评论等等~
题目描述
班上有 N 名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友。所谓的朋友圈,是指所有朋友的集合。
给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果 M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。
- N 在[1,200]的范围内。
- 对于所有学生,有 M[i][i] = 1。
- 如果有 M[i][j] = 1,则有 M[j][i] = 1。
题目样例
示例 1
输入
[[1,1,0],
[1,1,0], [0,0,1]]输出
2
解释
- 已知学生 0 和学生 1 互为朋友,他们在一个朋友圈。
- 第 2 个学生自己在一个朋友圈。所以返回 2。
示例 2
输入
[[1,1,0],
[1,1,1], [0,1,1]]输出
1
解释
已知学生 0 和学生 1 互为朋友,学生 1 和学生 2 互为朋友,所以学生 0 和学生 2 也是朋友,所以他们三个在一个朋友圈,返回 1。
题目思考
- 朋友圈的个数可以等价于什么呢?
解决方案
思路
- 分析
- 要求朋友圈个数, 我们只需要找到是朋友的学生, 把他们归类在一起即可, 最终朋友圈就是集合的个数
- 推导
- 由于朋友关系是相互的, 具有对称性, 所以我们只需要遍历单方朋友关系即可, 即只需要遍历 i=>j(i<=j)的关系
- 然后对于朋友关系, 将两者 union 起来即可
- 最后再遍历所有人找他们的祖先 (注意此处仍然需要调用 find 而不是直接拿 pre 字典中存的结果, 具体原因参见上篇文章
[Leetcode 每日精选](本周主题-并查集) 990. 等式方程的可满足性
), 把祖先放到集合里, 最后集合长度即为所求.
- 实现
- 下面的代码中对每个步骤都有注释, 方便大家理解
复杂度
- 时间复杂度 O(N^2logN): 需要两重循环, 然后每次带有路径压缩的并查集的操作复杂度为 O(logN)
- 空间复杂度 O(N): pre 字典中存 N 个元素
代码
Python 3
class Solution: def findCircleNum(self, M: List[List[int]]) -> int: # 经典并查集模板 # 祖先字典 pre = { } def find(x): # 找x的祖先 if x not in pre: # 祖先设为本身 pre[x] = x elif pre[x] != x: # 路径压缩, 更新当前祖先到更上面的祖先 pre[x] = find(pre[x]) return pre[x] def union(x, y): # 合并x和y到同一集合, 即把x的祖先的祖先指向y的祖先 pre[find(x)] = find(y) n = len(M) for i in range(n): for j in range(i, n): # 由于对称性, M[j][i]一定也是1, 所以此处只需要合并i和j即可, j不需要从头开始 if M[i][j] == 1: union(i, j) cntset = set() for i in range(n): # 注意这里使用find得到每个节点的最终祖先 cntset.add(find(i)) return len(cntset)
C++
class Solution { public: int findCircleNum(vector>& M) { unordered_map pre; function find = [&](int x) { if (pre.find(x) == pre.end()) { pre[x] = x; } else if (pre[x] != x) { pre[x] = find(pre[x]); } return pre[x]; }; auto Union = [&](int x, int y) { pre[find(x)] = find(y); }; for (int i = 0; i < M.size(); ++i) { for (int j = i; j < M.size(); ++j) { if (M[i][j]) { Union(i, j); } } } unordered_set cntset; for (int i = 0; i < M.size(); ++i) { cntset.insert(find(i)); } return cntset.size(); }};
大家可以在下面这些地方找到我~😊
我的公众号: 每日精选算法题, 欢迎大家扫码关注~😊
转载地址:https://blog.csdn.net/zjulyx1993/article/details/106650124 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
路过,博主的博客真漂亮。。
[***.116.15.85]2024年04月13日 23时19分33秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
初学ToggleButton 点击按钮,更换按钮背景图片;再次点击,恢复之前背景图
2019-04-29
Android 四种绑定监听事件的方式
2019-04-29
ViewPager+Fragment 滑动菜单效果 实现步骤
2019-04-29
eclipse下Ctrl+H搜索并替换全项目字符串
2019-04-29
Android注释规范
2019-04-29
代码动态设置图标的大小和位置的工具类
2019-04-29
Android Studio(2.3.3)配置Kotlin笔记
2019-04-29
用正则表达式判断邮箱命名是否合法
2019-04-29
lili‘s sqli-labs less01(简直是在为难我小猪崽)
2019-04-29
lili‘s sqli-labs less02(小猪崽有新发现)
2019-04-29
lili‘s sqli-labs LESS-3&LESS-4
2019-04-29
lili‘s LESS05前知识补充
2019-04-29
lili’s LESS05盲注!!(小猪崽觉得这是个什么玩意儿嘤嘤嘤)
2019-04-29
lili‘s sqli-labs LESS06
2019-04-29
lili’s sqli-labs LESS7,8,9,10 补充知识
2019-04-29
第一天收获
2019-04-29
第一周:Centos 7 基础命令
2019-04-29
centos 7 用户创建、用户/文件权限管理
2019-04-29