leecode/problems/547.friend-circles.md
2020-05-22 18:17:19 +08:00

87 lines
3.0 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 题目地址547. 朋友圈)
https://leetcode-cn.com/problems/friend-circles/
## 题目描述
班上有  N  名学生。其中有些人是朋友,有些则不是。他们的友谊具有是传递性。如果已知 A 是 B  的朋友B 是 C  的朋友,那么我们可以认为 A 也是 C  的朋友。所谓的朋友圈,是指所有朋友的集合。
给定一个  N \* N  的矩阵  M表示班级中学生之间的朋友关系。如果 M[i][j] = 1表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。
示例 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。
注意:
N 在[1,200]的范围内。
对于所有学生,有 M[i][i] = 1。
如果有 M[i][j] = 1则有 M[j][i] = 1。
## 思路
并查集有一个功能是可以轻松计算出连通分量,然而本题的朋友圈的个数,本质上就是连通分量的个数,因此用并查集可以完美解决。
为了简单更加清晰,我将并查集模板代码单尽量独拿出来。
## 代码
`find`, `union`, `connected` 都是典型的模板方法。 懂的同学可能也发现了,我没有做路径压缩,这直接导致 find union connected 的时间复杂度最差的情况退化到 $O(N)$。
当然优化也不难,我们只需要给每一个顶层元素设置一个 size 用来表示连通分量的大小,这样 union 的时候我们将小的拼接到大的上即可。 另外 find 的时候我们甚至可以路径压缩,将树高限定到常数,这样时间复杂度可以降低到 $O(1)$。
```python
class UF:
parent = {}
cnt = 0
def __init__(self, M):
n = len(M)
for i in range(n):
self.parent[i] = i
self.cnt += 1
def find(self, x):
while x != self.parent[x]:
x = self.parent[x]
return x
def union(self, p, q):
if self.connected(p, q): return
self.parent[self.find(p)] = self.find(q)
self.cnt -= 1
def connected(self, p, q):
return self.find(p) == self.find(q)
class Solution:
def findCircleNum(self, M: List[List[int]]) -> int:
n = len(M)
uf = UF(M)
for i in range(n):
for j in range(i):
if M[i][j] == 1:
uf.union(i, j)
return uf.cnt
```
**复杂度分析**
- 时间复杂度:平均 $O(logN)$,最坏的情况是 $O(N)$
- 空间复杂度:我们使用了 parent 因此空间复杂度为 $O(N)$
欢迎关注我的公众号《脑洞前端》获取更多更新鲜的 LeetCode 题解
![](https://pic.leetcode-cn.com/89ef69abbf02a2957838499a96ce3fbb26830aae52e3ab90392e328c2670cddc-file_1581478989502)