【LeetCode每日一题】924. 尽量减少恶意软件的传播(并查集)

文章目录


924. 尽量减少恶意软件的传播

思路:并查集
  1. 构建并查集:首先,代码创建了一个 UnionFind 类来维护节点之间的连通关系。它使用了并查集的数据结构,其中 p 数组存储每个节点的父节点,而 size 数组存储每个节点所在集合的大小。
  2. 遍历图并建立连接关系:接下来,代码遍历了给定的图 graph,并对图中存在连接的节点调用 union 方法,将它们所在的集合合并起来。
  3. 统计感染节点数:然后,代码统计了每个初始感染节点所在集合的感染节点数量,并更新了最小节点的值。
  4. 寻找优化的方案:接着,代码再次遍历了初始感染节点数组 initial,对每个节点进行如下操作:
    • 找到该节点所在集合的根节点。
    • 如果该集合中只有一个初始感染节点,那么比较该集合的大小和最大感染节点数,更新答案为当前节点和最大感染节点数。
  5. 返回结果:最后,代码返回了答案,如果没有找到优化的方案,则返回最小节点。
代码:
java 复制代码
class Solution {
    public int minMalwareSpread(int[][] graph, int[] initial) {
        int n = graph.length;
        UnionFind uf = new UnionFind(n);//用并查集维护节点的连通关系
        for (int i = 0; i < n; i++) {
            for (int j = i+1; j < n; j++) {
                if (graph[i][j] == 1) {//如果存在连接
                    uf.union(i, j);//将节点i和节点j所在的集合合并
                }
            }
        }
        int ans = n;
        int min = n;//最小结点
        int max = 0;//最大感染数
        int[] count = new int[n];
        for (int x : initial) {
            count[uf.find(x)]++;//统计每个初始感染节点所在集合的感染节点数量
            min = Math.min(min, x);//更新最小节点
        }
        for (int x : initial) {
            int root = uf.find(x);
            if (count[root] == 1) {
                int size = uf.size(root);
                if (size > max || (size == max && x < ans)) {
                    // 如果当前集合的大小大于最大感染节点数,或者当前集合的大小等于最大感染节点数但节点值较小
                    ans = x;//更新答案为当前节点
                    max = size;//更新最大感染节点数
                }
            }
        }
        return ans == n ? min : ans;//ans==n说明没找到优化的方案,直接返回最小的结点。
    }
}
class UnionFind {
    //维护节点之间的连通关系
    private final int[] p;//存储父结点
    private final int[] size;//存储每个结点所在集合的大小

    public UnionFind(int n) {
        p = new int[n];
        size = new int[n];
        for (int i = 0; i < n; i++) {
            p[i] = i;//把每个父结点设置为自己
            size[i] = 1;//每个集合的初始大小为1
        }
    }

    public int find(int x) {
        //查找结点所在集合的根节点
        if (p[x] != x) {
            //如果父结点不是自己
            p[x] = find(p[x]);
        }
        return p[x];
    }

    public boolean union(int a, int b) { // 将两个节点所在的集合合并
        int pa = find(a);
        int pb = find(b);
        if (pa == pb) {
            //根节点相同,说明两个结点已经是在一个集合中了。
            return false;
        }
        if (size[pa] > size[pb]) {
            p[pb] = pa;//将集合b连接到集合a上
            size[pa] += size[pb];//更新集合a的大小
        }else {
            p[pa] = pb;
            size[pb] += size[pa];
        }
        return true;
    }

    public int size(int root) {
         获取指定根节点所在集合的大小
        return size[root];
    }
}

点击移步博客主页,欢迎光临~

相关推荐
刚学HTML7 分钟前
leetcode 05 回文字符串
算法·leetcode
AC使者26 分钟前
#B1630. 数字走向4
算法
冠位观测者30 分钟前
【Leetcode 每日一题】2545. 根据第 K 场考试的分数排序
数据结构·算法·leetcode
@小码农44 分钟前
202411 第十六届蓝桥杯青少组 STEMA 考试真题 汇总
职场和发展·蓝桥杯
古希腊掌管学习的神1 小时前
[搜广推]王树森推荐系统笔记——曝光过滤 & Bloom Filter
算法·推荐算法
qystca1 小时前
洛谷 P1706 全排列问题 C语言
算法
古希腊掌管学习的神1 小时前
[LeetCode-Python版]相向双指针——611. 有效三角形的个数
开发语言·python·leetcode
浊酒南街1 小时前
决策树(理论知识1)
算法·决策树·机器学习
就爱学编程2 小时前
重生之我在异世界学编程之C语言小项目:通讯录
c语言·开发语言·数据结构·算法
ProcessOn官方账号2 小时前
如何绘制网络拓扑图?附详细分类解说和用户案例!
网络·职场和发展·流程图·拓扑学