leetcode No.200

并查集

leetcode第200题。
看到有人写的不错:https://leetcode-cn.com/problems/number-of-islands/solution/cyu-yan-bing-cha-ji-mo-ban-jian-yi-bei-xia-lai-by-/
收录下来。

// LeetCode200. 岛屿数量
// 给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
// 岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
// 此外,你可以假设该网格的四条边均被水包围。
// 提示:
// m == grid.length
// n == grid[i].length
// 1 <= m, n <= 300
// grid[i][j] 的值为 '0' 或 '1'

// 算法:并查集
// 重点:
// 1.UFInit()如何初始化,将实际问题映射为并查集
// 2.何时使用Union()将节点分类
// 3.如何使用Union()将节点分类

/* 并查集模板:权重平衡+路径压缩 */
int g_count;
int* g_parent;
int* g_size;    /* 权重:这棵树有多少个节点 */

/* 并查集的初始化 */
void UFInit(int n)
{
    g_count = n;
    g_parent = (int*)calloc(n, sizeof(int));
    if (g_parent == NULL) {
        printf("g_parent calloc fail\n");
        return;
    }

    g_size = (int*)calloc(n, sizeof(int));
    if (g_size == NULL) {
        printf("g_size calloc fail\n");
        return;
    }

    int i;
    for (i = 0; i < n; i++) {
        g_parent[i]= i; /* 父节点初始化为自己 */
        g_size[i] = 1;  /* 权重初始化为1 */
    }
}

/* 查找x的根节点 */
int Find(int x)
{
    while (x != g_parent[x]) {
        g_parent[x] = g_parent[g_parent[x]]; /* 路径压缩 */
        x = g_parent[x];
    }

    return x;
}

/* 将p和q连通 */
void Union(int p, int q)
{
    int rootP = Find(p);
    int rootQ = Find(q);

    if (rootP == rootQ) {
        return;
    }

    /* 根据权重,把小树挂在大树下面,然后连通分量减一 */
    if (g_size[rootP] < g_size[rootQ]) {
        g_parent[rootP] = rootQ;
        g_size[rootQ] += g_size[rootP];
    } else {
        g_parent[rootQ] = rootP;
        g_size[rootP] += g_size[rootQ];
    }

    g_count--;
}

/* 判断p和q是否连通 */
bool IsConnected(int p, int q)
{
    int rootP = Find(p);
    int rootQ = Find(q);

    return rootP == rootQ;
}

/* 返回当前的连通分量数目 */
int GetCount()
{
    return g_count;
}

// 算法:
// 1.虚构哑巴节点 dummy,把所有的0与之连通
// 2.把相邻的1连通
// 3.遍历结束后,获得当前连通分量,减去1个(0的连通),剩下的就是岛屿数量


int numIslands(char** grid, int gridSize, int* gridColSize)
{
    if (grid == NULL || gridSize < 1 || gridColSize == NULL) {
        return 0;
    }
    
    int m = gridSize;
    int n = gridColSize[0];
    int dummy = m * n;
    int ans;
    
    UFInit(m * n + 1);
    
    /* 方向数组 */
    int dir[4][2] = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
    
    int i;
    int j;
    for (i = 0; i < m; i++) {
        for (j = 0; j < n; j++) {
            if (grid[i][j] == '0') {
                Union(i * n + j, dummy);
                continue;
            }
            
            int k;
            for (k = 0; k < 4; k++) {
                int nx = i + dir[k][0];
                int ny = j + dir[k][1];
                
                if (nx >= 0 && nx < m && ny >= 0 && ny < n && grid[nx][ny] == '1') {
                    Union(nx * n + ny, i * n + j);
                }
            }        
        }
    }
    
    ans = GetCount() - 1;
    
    /* 最后记得释放内存 */
    free(g_parent);
    g_parent = NULL;
    free(g_size);
    g_size = NULL;
    
    return ans;
}

作者:little_bee
链接:https://leetcode-cn.com/problems/number-of-islands/solution/cyu-yan-bing-cha-ji-mo-ban-jian-yi-bei-xia-lai-by-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

还有个C with class的

#define ERROR -1
typedef struct{
    int n;
    int familyCnt;
    int* father;
    int* size;
}UnionFind;

UnionFind* unionFindCreate(int n){
    UnionFind* obj = (UnionFind*)malloc(sizeof(UnionFind));
    if (obj == NULL){
        return NULL;
    }
    obj->n = n;
    obj->familyCnt = n;
    obj->father = (int*)malloc(n * sizeof(int));
    obj->size = (int*)malloc(n * sizeof(int));
    if (obj->father == NULL || obj->size == NULL){
        free(obj->father);
        free(obj->size);
        free(obj);
        return NULL;
    }
    for (int i = 0; i < n; ++i){
        obj->father[i] = i;
        obj->size[i] = 1;
    }
    return obj;
}

int getFamilyCnt(UnionFind* obj){
    if (obj == NULL){
        return ERROR;
    }
    return obj->familyCnt;
}

int getFather(UnionFind* obj, int index){
    if (obj == NULL || index < 0 || index >= obj->n){
        return ERROR;
    }
    if (obj->father[index] == index){
        return index;
    }
    obj->father[index] = getFather(obj, obj->father[index]);
    return obj->father[index];
}

int connect(UnionFind* obj, int src, int dst){
    if (obj == NULL || src < 0 || src >= obj->n || dst < 0 || dst >= obj->n){
        return ERROR;
    }
    int src_father = getFather(obj, src);
    int dst_father = getFather(obj, dst);
    if (src_father == dst_father){
        return 0;
    }
    else{
        int src_size = obj->size[src_father];
        int dst_size = obj->size[dst_father];
        if (src_size > dst_size){
            obj->size[src_father] += obj->size[dst_father];
            obj->size[dst_father] = 0;
            (obj->father)[dst_father] = src_father;
            --obj->familyCnt;
        }
        else{
            obj->size[dst_father] += obj->size[src_father];
            obj->size[src_father] = 0;
            (obj->father)[src_father] = dst_father;
            --obj->familyCnt;
        }
        return 1;
    }
}

int getSize(UnionFind* obj, int index){
    if (obj == NULL || index < 0 || index >= obj->n){
        return ERROR;
    }
    return obj->size[getFather(obj, index)];
}

void unionFindFree(UnionFind* obj){
    if (obj != NULL){
        free(obj->father);
        free(obj->size);
        free(obj);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值