首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

【唐叔学算法】第八天:并查集-图论连通性的大杀器

  • 25-02-21 21:00
  • 2316
  • 9893
blog.csdn.net

你是否曾为如何高效地解决图论中的连通性问题而烦恼?并查集算法,就像一张无形的网,能帮你轻松连接所有节点。今天,就让我们一起揭开并查集算法的神秘面纱,探索它在Java编程中的应用。

并查集是什么?

并查集(Union-Find)是一种数据结构,用于处理一些不交集的合并及查询问题。它支持两种操作:

  • 合并(Union):将两个集合合并为一个集合。
  • 查询(Find):查询某个元素所属的集合。

并查集算法通常采用树形结构表示,每个节点包含一个指向父节点的指针。通过不断向上回溯,可以找到该节点所属的集合的代表元素。

并查集的应用场景

并查集算法广泛应用于以下场景:

  • 动态连通性问题:处理动态加入或删除边的情况。
  • 网络流问题:判断两个节点是否在同一个网络流中。
  • 图的连通性检测:判断两个顶点是否在同一个连通分量内。
  • 社交网络分析:判断两个用户是否属于同一个社交圈。
  • 等价类划分:将具有相同属性的元素划分到同一个集合中。

并查集的使用

使用并查集算法的关键在于:

  1. 初始化:创建一个并查集,并为每个元素设置一个父节点,指向自身。
  2. 查询(Find):使用路径压缩技术,将查询路径上的所有节点都指向代表元素,从而提高查询效率。
  3. 合并(Union):使用按秩合并技术,将两个集合合并为一个集合,并保持树的高度最小。

说明:

  • 路径压缩:在查找过程中,将查找路径上的所有节点直接指向根节点,以加速后续查找。
  • 按秩合并:在合并时,优先将较小的树合并到较大的树上,以保持树的平衡。

注意事项

在使用并查集算法时,需要注意以下几点:

  • 初始化:确保每个元素的初始状态正确,避免后续操作出错。
  • 路径压缩:可以显著提高查询效率,但会增加合并操作的复杂度。
  • 按秩合并:可以保持树的高度最小,从而提高查询和合并的效率。
  • 时间复杂度:并查集算法的查询和合并操作的平均时间复杂度通常为 O(α(n)),其中 α(n) 是阿克曼函数的反函数,增长非常缓慢。

LeetCode实战

入门题目 - 200. 岛屿数量

题目描述: 给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。

解题思路

将每个岛屿视为一个集合,通过并查集算法判断两个陆地单元格是否属于同一个岛屿。遍历所有单元格,如果是陆地,则将其与周围陆地单元格进行合并。

Java代码实现
public class Solution {
    public int numIslands(char[][] grid) {
        int m = grid.length, n = grid[0].length;
        UnionFind uf = new UnionFind(m * n);
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == '1') {
                    int idx = i * n + j;
                    if (i > 0 && grid[i - 1][j] == '1') {
                        uf.union(idx, (i - 1) * n + j);
                    }
                    if (j > 0 && grid[i][j - 1] == '1') {
                        uf.union(idx, i * n + (j - 1));
                    }
                }
            }
        }
        return uf.getCount();
    }
}

/**
 * 并查集类
 */
class UnionFind {
    private int[] parent;
    private int[] rank;
    private int count;

    public UnionFind(int size) {
        parent = new int[size];
        rank = new int[size];
        count = size;
        for (int i = 0; i < size; i++) {
            parent[i] = i;
            rank[i] = 0;
        }
    }

    public int find(int x) {
        if (parent[x] != x) {
            parent[x] = find(parent[x]);
        }
        return parent[x];
    }

    public void union(int x, int y) {
        int rootX = find(x);
        int rootY = find(y);
        if (rootX != rootY) {
            if (rank[rootX] < rank[rootY]) {
                parent[rootX] = rootY;
            } else if (rank[rootX] > rank[rootY]) {
                parent[rootY] = rootX;
            } else {
                parent[rootY] = rootX;
                rank[rootX]++;
            }
            count--;
        }
    }

    public int getCount() {
        return count;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

中等难度题目 - 547. 省份数量

题目描述: 有 n 个城市和一些双向连接这些城市的道路。每个城市与相邻城市直接相连,共计有 m 条道路。返回城市的省份数量。

解题思路

与岛屿数量类似,将每个城市视为一个集合,通过并查集算法判断两个城市是否属于同一个省份。遍历所有道路,将相邻城市进行合并。

Java代码实现
public int findCircleNum(int[][] isConnected) {
    int n = isConnected.length;
    UnionFind uf = new UnionFind(n);
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            if (isConnected[i][j] == 1) {
                uf.union(i, j);
            }
        }
    }
    return uf.getCount();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

更多LeetCode题目推荐

如果您对并查集算法感兴趣,希望挑战更多题目,以下是一些LeetCode上推荐的题目:

  • 130. 被围绕的区域

  • 399. 除法求值

  • 684. 冗余连接

  • 990. 等式方程的可满足性

结语

并查集算法就像一张无形的网,能帮你轻松连接所有节点。希望本文能让你对并查集算法有更深入的理解,并在实际编程中灵活运用。


如果喜欢这篇文章,别忘了点赞和分享哦!?我是唐叔,我们下期见。

注:本文转载自blog.csdn.net的唐叔在学习的文章"https://blog.csdn.net/Tang_is_learning/article/details/144334564"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

137
数学
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top