【练习题】Leetcode130&Leetcode547(并查集)

并查集详解参考https://blog.csdn.net/moX980/article/details/107782408

Leetcode130

在这里插入图片描述

题目分析:注意解释里的文字!!!将被X包围的O都连通在一起,而在边界上O都与某个特定的点连通(比如0),连通操作结束后,遍历一遍表,将没有与0连通的O改为X即可

注意并查集的表示方法是一个数组,将2*2的board转化为一维的,将0位空出用作连同边界上的O

遍历board:

  • 当board[i] [j] 为X时,跳过
  • 不为X就为O 当O在边界处,i == 0 || i == n-1 || j == 0 || j == m - 1,将这个位置与0连通
  • 当O不在边界处,检查此点的上左是否为O,为O连通(虽然不在边界处,但可能通过连通连接到边界的O)
class Solution {
public:
    class UnionSet{
    public:
        int *fa, *cnt;
        UnionSet(int n){
            fa = new int[n + 1];
            cnt = new int[n + 1];
            for(int i = 0; i <= n; i++){
                fa[i] = i;
                cnt[i] = 1;
            }
        }
        int find(int x){
            //路径压缩
            return fa[x] = (x == fa[x] ? x : find(fa[x]));
        }
        void merge(int a, int b){
            int aa = find(a), bb = find(b);
            if(aa == bb) return ;
            //按weighted优化
            if(cnt[aa] > cnt[bb]) swap(aa, bb);
            fa[bb] = aa;
            cnt[aa] += cnt[bb];
            return ;
        }
        ~UnionSet(){
            delete[] fa;
            delete[] cnt;
        }
    };
    int n, m;
    int ind(int i, int j){
        return i * m + j + 1;
    }

    void solve(vector<vector<char>>& board) {
        if(board.size() == 0) return ;
        n = board.size();
        m = board[0].size();
        UnionSet u(n * m);
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                if(board[i][j] == 'X') continue;
                if(i && board[i - 1][j] == 'O') u.merge(ind(i, j), ind(i - 1, j));
                if(j && board[i][j - 1] == 'O') u.merge(ind(i, j), ind(i, j - 1));
                if(i == 0 || i == n - 1) u.merge(0, ind(i, j));
                if(j == 0 || j == m - 1) u.merge(0, ind(i, j));
            }
        }
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                if(board[i][j] == 'X') continue;
                if(u.find(ind(i, j)) == u.find(0)) continue;
                board[i][j] = 'X';
            }
        }
        return ;
    }
};

Leetcode547

在这里插入图片描述

题目分析:并查集,遍历所给的表,如果ij为1,就连同i和j,连通操作结束后,遍历并查集,只要是fa[i] == i(自己是自己的父节点),说明自己是一个子树的根节点,有多少根节点就有多少朋友圈

class Solution {
public:
    class UnionSet{
    public:
        int *fa, *cnt;
        UnionSet(int n){
            fa = new int[n];
            cnt = new int[n];
            for(int i = 0; i < n; i++){
                fa[i] = i;
                cnt[i] = 1;
            }
        }
        int find(int x){
            return fa[x] = (x == fa[x] ? x : find(fa[x]));
        }
        void merge(int a, int b){
            int aa = find(a), bb = find(b);
            if(aa == bb) return ;
            if(cnt[aa] > cnt[bb]) swap(aa, bb);
            fa[aa] = bb;
            cnt[bb] += cnt[aa];
            return ;
        }
        ~UnionSet(){
            delete[] fa;
            delete[] cnt;
        }
    };

    int findCircleNum(vector<vector<int>>& M) {
        if(M.size() == 0) return 0;
        int n = M.size();
        UnionSet u(n);
        for(int i = 0; i < n; i++){
            for(int j = i + 1; j < n; j++){
                if(M[i][j] == 0) continue;
                u.merge(i, j);
            }
        }
        int ans = 0;
        for(int i = 0; i < n; i++){
            if(u.find(i) == i) ans++; 
        }
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沙diao网友

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值