并查集c++代码_[Leetcode 每日精选](本周主题-并查集) 547. 朋友圈
生活随笔
收集整理的這篇文章主要介紹了
并查集c++代码_[Leetcode 每日精选](本周主题-并查集) 547. 朋友圈
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目難度: 中等
原題鏈接
今天繼續來做并查集的問題, 這道題仍然比較基礎, 而且也是個比較接近現實的問題了. 大家在我的公眾號"每日精選算法題"中的聊天框中回復 并查集 就能看到該系列當前已經更新的文章了
大家有什么想法建議和反饋的話歡迎隨時交流, 包括但不限于公眾號聊天框/知乎私信評論等等~
題目描述
班上有 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] = xelif 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<vector<int>>& M) {unordered_map<int, int> pre;function<int(int)> 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<int> cntset;for (int i = 0; i < M.size(); ++i) {cntset.insert(find(i));}return cntset.size();}
};
大家可以在下面這些地方找到我~
我的知乎專欄
我的 CSDN
我的 Leetcode
我的牛客網博客
我的公眾號: 每日精選算法題, 歡迎大家掃碼關注~
總結
以上是生活随笔為你收集整理的并查集c++代码_[Leetcode 每日精选](本周主题-并查集) 547. 朋友圈的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 求一个好听的男英文名字!
- 下一篇: mysql err 1349_MySQL