684 冗余连接
并查集-01
class Solution {
public int[] findRedundantConnection(int[][] edges) {
int n=edges.length;
int[] father=new int[n+1];
int i=n-1;
for(;i>0;i--){
if(findNum(edges,father,i,n)==1){
break;
}
}
return edges[i];
}
public int findNum(int[][] edges,int[] father,int len,int n){
int counts=0;
for(int i=1;i<=n;i++){
father[i]=i;
}
for(int i=n-1;i>=0;i--){
if(i==len){
continue;
}
union(father,edges[i][0],edges[i][1]);
}
for(int i=1;i<=n;i++){
if(father[i]==i){
counts++;
}
}
return counts;
}
public int find (int[] father,int a){
//路径压缩:把沿途的每个节点的父节点都设为根节点
if(father[a]!=a){
father[a]=find(father,father[a]);
}
return father[a];
}
public void union(int[] father,int a,int b){
//合并操作:先找到两个集合的代表元素,然后将前者的父节点设为后者即可。
//a的父节点是b
father[find(father,a)]=find(father,b);
}
}
时间复杂度
O
(
n
2
log
n
)
O(n^2\log n)
O(n2logn)。
空间复杂度
O
(
n
)
O(n)
O(n)。
并查集-02
树是一个连通且无环的无向图,在树中多了一条附件的边之后就会出现环,因此附加的边就是导致环出现的边。
可以通过并查集寻找附加的边。初始时,每个节点都属于不同的连通分量。遍历每一条边,判断这条边连接的两个顶点是否属于相同的连通分量。
- 如果两个顶点属于不同的连通分量,则说明在遍历到当前的边之前,这两个顶点之间不连通,因此当前的边不会导致环出现,合并这两个顶点的连通分量。
- 如果两个顶点属于相同的连通分量,则说明在遍历到当前的边之前,这两个顶点之间已经连通,因此当前的边导致环出现,为附加的边,将当前的边作为答案返回。
class Solution {
public int[] findRedundantConnection(int[][] edges) {
int n=edges.length;
int[] father=new int[n+1];
int i=0;
for(int j=1;j<=n;j++){
father[j]=j;
}
for(;i<n;i++){
if(find(father,edges[i][0])!=find(father,edges[i][1])){
//未连通
//则合并
union(father,edges[i][0],edges[i][1]);
}else{
break;
}
}
return edges[i];
}
public int find (int[] father,int a){
if(father[a]!=a){
father[a]=find(father,father[a]);
}
return father[a];
}
public void union(int[] father,int a,int b){
//a的父节点是b
father[find(father,a)]=find(father,b);
}
}
时间复杂度
O
(
n
log
n
)
O(n\log n)
O(nlogn),其中
n
n
n是图中的节点个数。需要遍历图中的
n
n
n条边,对于每条边,需要对两个节点找祖先,如果两个节点的祖先不同则需要进行合并,需要进行
2
2
2次查找和最多
1
1
1次合并。一共需要进行
2
n
2n
2n次查找和最多
n
n
n次合并。
空间复杂度
O
(
n
)
O(n)
O(n)。