Union find
有一颗二叉树
C D
A B
C指向的结点D, A和B指向结点C 下图 上一行是子节点 下一行是父亲节点 如果要找A的big father的话,先从A找到C,再从C找到D
并查集 查找 find 要O(n)的时间复杂度 union需要O(n)的时间复杂度
重要: 如果有一个链表,这个链表最后都指向最后一个元素,now you wanna find big father. now you set two pointers, now and temp
A—B—C—D (此时此刻now 指向A,temp指向B, 向右移动指针)
从第一个节点A开始遍历,最后找打big father是D,这个时候 将A的next指向B
变成这样的数据结构之后,find的时间复杂度就是O(1)
合并Union (找老大哥合并)
并查集的写法有2种,第一种是代码比较多,但是比较好理解,这种方法在union方法里面写的比较多,在find写的比少。只需要返回father数组index对应的数值就可以了.
public class UnionFind {
int[] ids;
int cnt;
public UnionFind(int size){
this.ids = new int[size];
//初始化并查集,每个节点对应自己的集合号
for(int i = 0; i < this.ids.length; i++){
this.ids[i] = i;
}
this.cnt = size;
}
public boolean union(int m, int n){
int src = find(m);
int dst = find(n);
//如果两个节点不在同一集合中,将两个集合合并为一个
if(src != dst){
for(int i = 0; i < ids.length; i++){
if(ids[i] == src){
ids[i] = dst;
}
}
// 合并完集合后,集合数减一
cnt--;
return true;
} else {
return false;
}
}
public int find(int m){
return ids[m];
}
public boolean areConnected(int m, int n){
return find(m) == find(n);
}
public int count(){
return cnt;
}
}
第二种,就是类似于递归的写法,这个方法不是递归,比递归写法更容易理解。father数组index对应的数并没有改过来,只是通过改过的数去按图索骥寻找最终的那个father
public class Solution {
public int longestConsecutive(int[] nums) {
UF uf = new UF(nums.length);
Map<Integer,Integer> map = new HashMap<Integer,Integer>(); // <value,index>
for(int i=0; i<nums.length; i++){
if(map.containsKey(nums[i])){
continue;
}
map.put(nums[i],i);
if(map.containsKey(nums[i]+1)){
uf.union(i,map.get(nums[i]+1));
}
if(map.containsKey(nums[i]-1)){
uf.union(i,map.get(nums[i]-1));
}
}
return uf.maxUnion();
}
}
class UF{
private int[] list;
public UF(int n){
list = new int[n];
for(int i=0; i<n; i++){
list[i] = i;
}
}
private int root(int i){
while(i!=list[i]){
list[i] = list[list[i]];
i = list[i];
}
return i;
}
public boolean connected(int i, int j){
return root(i) == root(j);
}
public void union(int p, int q){
int i = root(p);
int j = root(q);
list[i] = j;
}
// returns the maxium size of union
public int maxUnion(){ // O(n)
int[] count = new int[list.length];
int max = 0;
for(int i=0; i<list.length; i++){
count[root(i)] ++;
max = Math.max(max, count[root(i)]);
}
return max;
}
}
好好体会