並查集

主要內容

本文主要記錄並查集的基本實現方法,並逐步將一些例題填充到文章中。ide

並查集能作什麼

並查集能夠:
1. 合併集合
2. 查找兩個元素是否在同一個集合內
3. 集合數量
4. 肯定元素屬於哪一個集合函數

完整代碼示例

class UF
{
public:
    UF();
    UF(int N);
    ~UF();
    bool isConnected(int p, int q);
    int findRoot(int p);//查找根節點 主要函數
    void  unionSet(int p, int q);//合併集合 主要函數
    int getSetCount();
    int getElemCount();
    
private:
    std::vector<int> m_parent;
    std::vector<int> m_rank;
    int m_setCount; //集合個數
    int m_elemCount; //元素個數
};

UF::UF()
{
    m_setCount = 0;
    m_elemCount = 0;
}
UF::UF(int N):
    m_setCount(N), 
    m_elemCount(N)
{
    m_parent.resize(N);
    m_rank.resize(N);
    for(int i = 0; i < N; ++i)
    {
        m_parent[i] = i;
        m_rank[i] = 1;
    }
}
UF::~UF()
{
    
}


int UF::findRoot( int p )
{
    if(p != m_parent[p])
    {
        m_parent[p] = findRoot(m_parent[p]);
    }
    return m_parent[p];
}

void UF::unionSet(int p, int q )
{
    int rootOfP = findRoot(p);
    int rootOfQ = findRoot(q);
    if( rootOfP == rootOfQ ) 
        return ;
        
    if(m_rank[rootOfP] > m_rank[rootOfQ])
    {
        m_parent[rootOfQ] = rootOfP;
    }
    else
    {
        if(m_rank[rootOfP] == m_rank[rootOfQ])
        {
            m_rank[rootOfQ]++;
        }
        m_parent[rootOfP] = rootOfQ; 
    }
    m_setCount--;
}

bool UF::isConnected( int p, int q)
{
    return findRoot(p) == findRoot(q);
}

例題

LeetCode 547 朋友圈

班上有 N 名學生。其中有些人是朋友,有些則不是。他們的友誼具備是傳遞性。若是已知 A 是 B 的朋友,B 是 C 的朋友,那麼咱們能夠認爲 A 也是 C 的朋友。所謂的朋友圈,是指全部朋友的集合。code

給定一個 N * N 的矩陣 M,表示班級中學生之間的朋友關係。若是M[i][j] = 1,表示已知第 i 個和 j 個學生互爲朋友關係,不然爲不知道。你必須輸出全部學生中的已知的朋友圈總數。leetcode

示例 1:get

輸入:
[[1,1,0],
[1,1,0],
[0,0,1]]
輸出: 2
說明:已知學生0和學生1互爲朋友,他們在一個朋友圈。
第2個學生本身在一個朋友圈。因此返回2。io

示例 2:class

輸入:
[[1,1,0],
[1,1,1],
[0,1,1]]
輸出: 1
說明:已知學生0和學生1互爲朋友,學生1和學生2互爲朋友,因此學生0和學生2也是朋友,因此他們三個在一個朋友圈,返回1。nio

注意方法

N 在[1,200]的範圍內。
對於全部學生,有M[i][i] = 1。
若是有M[i][j] = 1,則有M[j][i] = 1。集合

class Solution {
public:
    int findCircleNum(vector<vector<int>>& M) {
        N = M.size();
        count = N;
        parent.resize(count);
        rank.resize(count);
        for(int i = 0; i < N; i++)
        {
            parent[i] = i;
            rank[i] = 1;
        }
        for(int i = 0; i < N -1 ; ++i)
        {
            for(int j = i + 1; j < N; ++j)
            {
                if(M[i][j] == 1)
                {
                    uni(i,j);
                }
            }
                
        }
        
        return count;
        
    }
    int root(int p)
    {
        if(p != parent[p])
        {
            parent[p] = root(parent[p]);
        }
        return parent[p];
    }
    void uni(int p, int q)
    {
        int proot = root(p);
        int qroot = root(q);
        if(proot == qroot) return ;
        
        if(rank[proot] > rank[qroot])
        {
            parent[qroot] = proot;
        }
        else
        {
            if(rank[proot] == rank[qroot])
            {
                rank[qroot]++;
            }
            parent[proot] = qroot;
        }
        count--;
        
    }
    
    
    
    int N;
    vector<int> parent;
    vector<int> rank;
    int count;
};

LeetCode 130 被圍繞的區域

給定一個二維的矩陣,包含 'X' 和 'O'(字母 O)。

找到全部被 'X' 圍繞的區域,並將這些區域裏全部的 'O' 用 'X' 填充。

示例:

X X X X
X O O X
X X O X
X O X X

運行你的函數後,矩陣變爲:

X X X X
X X X X
X X X X
X O X X

解釋:

被圍繞的區間不會存在於邊界上,換句話說,任何邊界上的 'O' 都不會被填充爲 'X'。 任何不在邊界上,或不與邊界上的 'O' 相連的 'O' 最終都會被填充爲 'X'。若是兩個元素在水平或垂直方向相鄰,則稱它們是「相連」的。

class Solution {
public:
    void solve(vector<vector<char>>& board) {
        if(board.size()==0||board[0].size()==0)return;
        h = board.size();
        w = board[0].size();
        len = h*w;
        parent.resize(len);
        rank.resize(len);
        isSide.resize(len);
        for(int i = 0; i < len; i++)
        {
            int x = i/w;
            int y = i%w;
            
            parent[i] = i;
            rank[i] = 1;
            
            if(x == 0 || x == h-1 || y == 0 || y == w-1)
            {
                if(board[x][y] == 'O')
                    isSide[i] = true;
            }
            else
            {
                isSide[i] = false;
            }
        }
        for(int i = 1; i < h; ++i)
        {
            for(int j = 1; j < w; ++j)
            {
                if(board[i][j-1] == board[i][j]) uni(i*w+j,i*w+j-1);
                if(board[i-1][j] == board[i][j]) uni(i*w+j,(i-1)*w+j);
            }
        }
        for(int i = 0; i < len; i++)
        {
            if(board[i/w][i%w] == 'O' && !isSide[root(i)])
                board[i/w][i%w] = 'X';
        }
    }
    int root(int p)
    {
        if(p != parent[p])
        {
            parent[p] = root(parent[p]);
        }
        return parent[p];
    }
    void uni(int p, int q)
    {
        int proot = root(p);
        int qroot = root(q);
        
        if(proot == qroot) return ;
        
        if(rank[proot] > rank[qroot])
        {
            parent[qroot] = proot;
        }
        else
        {
            if(rank[proot] = rank[qroot])
            {
                rank[qroot]++;
            }
            parent[proot] = qroot;
        }
        if(isSide[proot]) isSide[qroot] = true;
        if(isSide[qroot]) isSide[proot] = true;
    }
    vector<int> parent;
    vector<int> rank;
    vector<bool> isSide;
    
    int h;
    int w;
    int len;
};
相關文章
相關標籤/搜索