zoukankan      html  css  js  c++  java
  • 并查集(Union Find)

    特点

    常用于确定无向图的连通分量(虽然DFS也可以做),求最小公共祖先(LCA)

    朴素版并查集

        vector<int> v;
        void Union(int i, int j){
            int pi = Find(i);
            int pj = Find(j);
            
            v[pi] = pj;
        }
        
        int Find(int i){
            
            while(v[i] != i) i = v[i];
            
            return i;
        }
    

    路径压缩

    为了减少树的高度,直接将查找路径上的结点连接到根上去,降低查找时间

        int Find(int i){
            if(v[i] != i) v[i] = Find(v[i]);
            return v[i];
        }
    

    按秩合并

    秩表示结点高度的上界,(算法导论上说路径压缩不会改变每个结点的秩?没想通,难道是指的上界),将秩小的树指向秩大的树称为按秩合并

        void Union(int i, int j){
            int ri = Find(i);
            int rj = Find(j);
            if(ri == rj) return ;
    
            if(Rank[ri] > Rank[rj]){
                v[rj] = ri;
            } else if(Rank[ri] < Rank[rj]){
                v[ri] = rj;
            } else {
                Rank[ri] += 1;
                v[rj] = ri;
            }
        }
    

    时间复杂度

    朴素版并查集的Union操作的摊还时间为(O(n))
    使用按秩合并的Union操作的摊还时间为(O(log_2 n))
    同时采用按秩合并和路径压缩的最坏运行时间每个操作的摊还时间为(alpha(n))(反阿克曼函数,近似为一个常数)
    详细分析可以写一本书...

    例题

    547. Friend Circles

    class Solution {
    private:
        vector<int> Rank;
        vector<int> v;
    
         void Union(int i, int j){
            int ri = Find(i);
            int rj = Find(j);
            if(ri == rj) return ;
    
            if(Rank[ri] > Rank[rj]){
                v[rj] = ri;
            } else if(Rank[ri] < Rank[rj]){
                v[ri] = rj;
            } else {
                Rank[ri] += 1;
                v[rj] = ri;
            }
        }
        
        int Find(int i){
            if(v[i] != i) v[i] = Find(v[i]);
            return v[i];
        }
        
    public:
        int findCircleNum(vector<vector<int>>& M) {
            int n = M.size();
            for(int i = 0; i < n; i++){
                v.push_back(i);
                Rank.push_back(0);
            }
            
            for(int i = 0; i < n; i++){
                for(int j = i + 1; j < n; j++){
                    if(M[i][j] == 1){
                        Union(i, j);
                    }
                }
            }
            
            
            int cnt = 0;
            
            for(int i = 0; i < n; i++){
                if(Find(i) == i) cnt++;
            }
            
            return cnt;
        }
    };
    
  • 相关阅读:
    Candy leetcode java
    Trapping Rain Water leetcode java
    Best Time to Buy and Sell Stock III leetcode java
    Best Time to Buy and Sell Stock II leetcode java
    Best Time to Buy and Sell Stock leetcode java
    Maximum Subarray leetcode java
    Word Break II leetcode java
    Word Break leetcode java
    Anagrams leetcode java
    Clone Graph leetcode java(DFS and BFS 基础)
  • 原文地址:https://www.cnblogs.com/qbits/p/10974667.html
Copyright © 2011-2022 走看看