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

时间:2024-04-22 22:14:24
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]; } }