算法與數據結構基礎 - 合並查找(Union Find)


Union Find算法基礎

Union Find算法用於處理集合的合並和查詢問題,其定義了兩個用於並查集的操作:

  • Find: 確定元素屬於哪一個子集,或判斷兩個元素是否屬於同一子集
  • Union: 將兩個子集合並為一個子集

並查集是一種樹形的數據結構,其可用數組或unordered_map表示:

Find操作即查找元素的root,當兩元素root相同時判定他們屬於同一個子集;Union操作即通過修改元素的root(或修改parent)合並子集,下面兩個圖展示了id[6]由6修改為9的變化:

  

圖片來源 這里

 

Union Find算法應用

Union Find可用於解決集合相關問題,如判斷某元素是否屬於集合、兩個元素是否屬同一集合、求解集合個數等,算法框架如下:

    //261. Graph Valid Tree
    bool validTree(int n, vector<pair<int, int>>& edges) {
        vector<int> num(n,-1);
        for(auto edge:edges){
            //find查看兩點是否已在同一集合
            int x=find(num,edge.first);
            int y=find(num,edge.second);
            if(x==y) return false;  //兩點已在同一集合情況下則出現環
            //union讓兩點加入同一集合
            num[x]=y;
        }
        return n-1==edges.size();
    }
    int find(vector<int>&num,int i){
        if(num[i]==-1) return i;
        return find(num,num[i]);  //id[id[...id[i]...]]
    }

一些情況下為清晰和解偶會將Uinon Find實現為一個類,獨立出明顯的Union和Find兩個操作。

相關LeetCode題:

261. Graph Valid Tree  題解

547. Friend Circles  題解

947. Most Stones Removed with Same Row or Column  題解

200. Number of Islands  題解

 

算法優化

有兩種常用的方法用來降低並查集樹形結構的高度、以減少Uinon Find算法的時間復雜度,這兩種方法是:

Weighting(或稱作Ranking): 使用多一個數組記錄每個集合的size,Uinon時將size小的集合掛到size大的集合下,例如:

對3、5 Uinon,因3所在集合元素size 4大於5所在集合元素size 2,將6掛到9下而不是將9掛到6下。

Path compression: 對一個集合下的元素直接掛到root之下,而不是掛到其parent,path compression實現很簡單只需在Find中加一行代碼:

    string find(unordered_map<string,string>& root,string s){
        if(root[s]!=s) 
            root[s]=find(root,root[s]); return root[s];
    }

加入path compression也能實現減少並查集樹高度的效果,圖示如下:

 

Weighting和Path compression兩種方法可以同時使用,這樣使得對N個元素進行M次Union Find操作的時間復雜度可以減少到 (M+N)lgN。因lgN隨N的增長變化很小,所以整體算法時間復雜度接近於線性的時間復雜度。

 

相關LeetCode題:

924. Minimize Malware Spread  題解

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM