九章算法笔记:Union find

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;
        }
    }

好好体会

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值