zoukankan      html  css  js  c++  java
  • 并查集

    主要内容

    本文主要记录并查集的基本实现方法,并逐步将一些例题填充到文章中。

    并查集能做什么

    并查集可以:
    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 的朋友。所谓的朋友圈,是指所有朋友的集合。

    给定一个 N * N 的矩阵 M,表示班级中学生之间的朋友关系。如果M[i][j] = 1,表示已知第 i 个和 j 个学生互为朋友关系,否则为不知道。你必须输出所有学生中的已知的朋友圈总数。

    示例 1:

    输入:
    [[1,1,0],
    [1,1,0],
    [0,0,1]]
    输出: 2
    说明:已知学生0和学生1互为朋友,他们在一个朋友圈。
    第2个学生自己在一个朋友圈。所以返回2。

    示例 2:

    输入:
    [[1,1,0],
    [1,1,1],
    [0,1,1]]
    输出: 1
    说明:已知学生0和学生1互为朋友,学生1和学生2互为朋友,所以学生0和学生2也是朋友,所以他们三个在一个朋友圈,返回1。

    注意

    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;
    };
    
    
    
  • 相关阅读:
    “中国半导体教父”张汝京:中国半导体只缺人才
    集群搭建
    Scrapy
    商品建模
    python wordcloud
    StaticFileMiddleware中间件如何处理针对文件请求
    Docker / CI / CD
    NET Memory Profiler 跟踪.net 应用内存
    SOS.dll (SOS Debugging Extension)
    Download the WDK, WinDbg, and associated tools
  • 原文地址:https://www.cnblogs.com/xdblog/p/9652218.html
Copyright © 2011-2022 走看看