并查集简单使用
文章目錄
- 并查集--判斷圖上是否有環
- Leetcode冗余鏈接
- Leetcode島嶼數量
- 牛客網-找朋友
啥是并查集?
并查集是用來合并不相交集合的數據結構,一個常用的地方是判斷圖上是否有環。
并查集–判斷圖上是否有環
下面這幅圖中有環,如何判斷是否有圖?判斷兩個集合中元素是否有共同樹根。
分成兩個集合A和B
對于集合A,取1為樹根;對于集合B,取3為樹根。如果(1,3)之間有邊,則A和B是構成一個集合。這時候A,B中的任意兩個頂點之間存在邊,,如(2,4)之間存在邊,就說明該圖有環。
步驟
下面是沒有按秩合并的代碼,容易使得樹的高度過高。
代碼
測試
int main(){int parent[VERTICES]={0};initialise(parent);int edges[6][2]={//六條邊 {0,1},{1,2},{1,3},{2,4},{2,5},{3,4}};for(int i=0;i<6;i++){//六條邊 int x=edges[i][0];int y=edges[i][1];if(union_vertices(x,y,parent)==0){cout<<"cycle detected"<<endl;exit(0);} }cout<<"No cycles found"<<endl;}上述沒有按秩合并
按秩合并需要引入數的高度數組rank [ ],記錄樹的高度,原則是 矮的樹掛到高的樹上。
壓縮路徑之后的Union_vertices()函數
int union_vertices(int x,int y,int parent[],int rank[]){int x_root=find_root(x,parent);int y_root=find_root(y,parent);if(x_root==y_root) return 0;else{if(rank[x_root]>rank[y_root])parent[y_root]=x_root;else if(rank[x_root]<rank[y_root])parent[x_root]=y_root;else{//樹高相同parent[x_root]=y_root;rank[y_root]++; }return 1;} }完整并查集測試代碼
#include<iostream> #include<cstdlib> using namespace std; #define VERTICES 6void initialise(int parent[],int rank[]){int i;for(int i=0;i<VERTICES;i++){parent[i]=-1;//表示獨立節點 rank[i]=0;} } int find_root(int x ,int parent[]) {int x_root =x;while(parent[x_root]!=-1){x_root=parent[x_root];}return x_root; }int union_vertices(int x,int y,int parent[],int rank[]){int x_root=find_root(x,parent);int y_root=find_root(y,parent);if(x_root==y_root) return 0;else{if(rank[x_root]>rank[y_root])parent[y_root]=x_root;else if(rank[x_root]<rank[y_root])parent[x_root]=y_root;else{parent[x_root]=y_root;rank[y_root]++; }return 1;} }int main(){int parent[VERTICES]={0};int rank[VERTICES]={0}; initialise(parent,rank);int edges[6][2]={//六條邊 {0,1},{1,2},{1,3},{2,4},{2,5},{3,4}};for(int i=0;i<6;i++){//六條邊 int x=edges[i][0];int y=edges[i][1];if(union_vertices(x,y,parent,rank)==0){cout<<"Cycle detected"<<endl;exit(0);} }cout<<"No cycles found"<<endl;}該測試代碼檢測上述圖中是否有環
下面附上一道Leetcode題目
Leetcode冗余鏈接
在本問題中, 樹指的是一個連通且無環的無向圖。
輸入一個圖,該圖由一個有著N個節點 (節點值不重復1, 2, …, N) 的樹及一條附加的邊構成。附加的邊的兩個頂點包含在1到N中間,這條附加的邊不屬于樹中已存在的邊。
結果圖是一個以邊組成的二維數組。每一個邊的元素是一對[u, v] ,滿足 u < v,表示連接頂點u 和v的無向圖的邊。
返回一條可以刪去的邊,使得結果圖是一個有著N個節點的樹。如果有多個答案,則返回二維數組中最后出現的邊。答案邊 [u, v] 應滿足相同的格式 u < v。
示例 1:
輸入: [[1,2], [1,3], [2,3]]
輸出: [2,3]
解釋: 給定的無向圖為:
示例 2:
輸入: [[1,2], [2,3], [3,4], [1,4], [1,5]]
輸出: [1,4]
解釋: 給定的無向圖為:
注意:
輸入的二維數組大小在 3 到 1000。
二維數組中的整數在1到N之間,其中N是輸入數組的大小。
代碼
分為兩部分,上面是并查集原封不動,下面是調用Union函數來進行判斷是否有環。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/redundant-connection
著作權歸領扣網絡所有。商業轉載請聯系官方授權,非商業轉載請注明出處。
Leetcode 200
Leetcode島嶼數量
給你一個由 ‘1’(陸地)和 ‘0’(水)組成的的二維網格,請你計算網格中島嶼的數量。
島嶼總是被水包圍,并且每座島嶼只能由水平方向和/或豎直方向上相鄰的陸地連接形成。
此外,你可以假設該網格的四條邊均被水包圍。
示例 1:
輸入:
11110
11010
11000
00000
輸出: 1
示例 2:
輸入:
11000
11000
00100
00011
輸出: 3
解釋: 每座島嶼只能由水平和/或豎直方向上相鄰的陸地連接而成。
分析
并查集解法
合并時,判斷左邊和上邊位置。不需要判斷下邊和右邊。
代碼
class Solution { public:vector<int> parents_;vector<int> ranks_;int find(int x){if(x!=parents_[x])parents_[x]=find(parents_[x]);return parents_[x];}void Union(int x, int y){int fx=find(x);int fy=find(y);if(ranks_[fx]==ranks_[fy]){parents_[fx]=fy;ranks_[fy]++;}else if(ranks_[fx]<ranks_[fy])parents_[fx]=fy;else parents_[fy]=fx;}int numIslands(vector<vector<char>>& grid) {if(grid.size()==0 ) return 0;int m=grid.size();int n=grid[0].size();if(n==1 && m==1) {if(grid[0][0]=='1') return 1;else return 0;}for(int i=0;i<m*n;i++){parents_.push_back(i);ranks_.push_back(0);}for(int i=0;i<m;i++)for(int j=0;j<n;j++){if(grid[i][j]=='0') continue;int cur_pos=i*n+j;//坐標轉換//上邊if(i>0&&grid[i-1][j]=='1') Union(cur_pos-n,cur_pos);//左邊if(j>0&&grid[i][j-1]=='1')Union(cur_pos,cur_pos-1);}int count=0;for(int i=0;i<m;i++)for(int j=0;j<n;j++){int cur_pos=i*n+j;if(cur_pos==find(cur_pos)&&grid[i][j]=='1')count++;}return count;} };來源:力扣(LeetCode)
鏈接:島嶼數量https://leetcode-cn.com/problems/number-of-islands
著作權歸領扣網絡所有。商業轉載請聯系官方授權,非商業轉載請注明出處。
牛客網-找朋友
找朋友并查集裸題
總結
- 上一篇: 最长上升子序列(LIS) nlogn解法
- 下一篇: vector嵌套vector嵌套pair