1. 程式人生 > >九章演算法筆記:Union find

九章演算法筆記: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;
        }
    }

好好體會