問題說明
聯合查詢主要用於檢查圖裏面是否有迴環。
本文主要圍繞leetcode上的這個題介紹。
聯合集的概念及聯合查詢
聯合集假設初始時,所有的元素都在不同的set內,連接兩個元素後,這兩個元素就屬於同一個set。leetcode684的題就是可以用聯合集來做:
剛開始假設所有的節點都在不同的set內,連接兩個節點之後就設置這兩個節點在同一個set。當新加入的某一條邊的兩個節點都在同一個set,就說明這兩個節點已經可以通過一定的路徑連接了,所以新加入的邊就是冗餘邊。
演示
假設現在有6個節點1-6,我們向這些節點加入邊。初始化時節點及對應的集合如下:
節點 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
所屬集合 | 1 | 2 | 3 | 4 | 5 | 6 |
加入邊3-6後的節點及對應集合:
節點 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
所屬集合 | 1 | 2 | 6 | 4 | 5 | 6 |
加入邊1-3後的節點及對應集合:
節點 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
所屬集合 | 6 | 2 | 6 | 4 | 5 | 6 |
加入邊1-6。加入邊之前可以發現1、6這兩個節點已經屬於同一個set,因此1-6這條邊是冗餘邊。
聯合方法
684涉及到的方法只有兩個:一個是查找一個節點屬於哪個集合;一個是當兩個節點不在同一個set時,將他們歸併到同一個set。
class Solution {
public int[] findRedundantConnection(int[][] edges) {
int[] us=new int[2000];
for(int i=0;i<2000;i++)
us[i]=i;
for(int[] e:edges) {
if(findSet(e[0], us)==findSet(e[1], us))
return e;
union(e[0],e[1], us);
}
return null;
}
private int findSet(int num, int[] us) {
if(num==us[num]) return num;
while(us[num]!=num)
num=us[num];
return num;
}
private void union(int start, int end, int[] us) {
int startSet = findSet(start, us);
int endSet = findSet(end, us);
if(startSet!=endSet) {
us[startSet]=endSet;
}
}
}