924. 尽量减少恶意软件的传播
给出了一个由 n 个节点组成的网络,用 n × n 个邻接矩阵图 graph 表示。在节点网络中,当 graph[i][j] = 1 时,表示节点 i 能够直接连接到另一个节点 j。
一些节点 initial 最初被恶意软件感染。只要两个节点直接连接,且其中至少一个节点受到恶意软件的感染,那么两个节点都将被恶意软件感染。这种恶意软件的传播将继续,直到没有更多的节点可以被这种方式感染。
假设 M(initial) 是在恶意软件停止传播之后,整个网络中感染恶意软件的最终节点数。
如果从 initial 中移除某一节点能够最小化 M(initial), 返回该节点。如果有多个节点满足条件,就返回索引最小的节点。
请注意,如果某个节点已从受感染节点的列表 initial 中删除,它以后仍有可能因恶意软件传播而受到感染。
示例 1:
输入: graph = [[1,1,0],[1,1,0],[0,0,1]], initial = [0,1]
输出: 0
示例 2:
输入: graph = [[1,0,0],[0,1,0],[0,0,1]], initial = [0,2]
输出: 0
示例 3:
输入: graph = [[1,1,1],[1,1,1],[1,1,1]], initial = [1,2]
输出: 1
提示:
n == graph.lengthn == graph[i].length2 <= n <= 300graph[i][j] == 0或1.graph[i][j] == graph[j][i]graph[i][i] == 11 <= initial.length <= n0 <= initial[i] <= n - 1initial中所有整数均不重复
/**
* @param {number[][]} graph
* @param {number[]} initial
* @return {number}
*/
var minMalwareSpread = function(graph, initial) {
const n = graph.length;
const unionFind = new UnionFind(n);
for (let i = 0; i < n; i++) {
for (let j = i + 1; j < n; j++) {
if (graph[i][j]) {
unionFind.union(i, j);
}
}
}
const temp = {};
let result = Number.MAX_VALUE;
for (const i of initial) {
result = Math.min(result, i);
const rootNode = unionFind.find(i);
if (temp[rootNode]) {
temp[rootNode].num++;
} else {
temp[rootNode] = {
num: 1
}
}
if (temp[rootNode].num === 1) {
temp[rootNode].nodeId = i;
}
}
let maxSize = 0;
for (let key in temp) {
if (temp[key].num === 1) {
const size = unionFind.getSize(key);
if (size > maxSize) {
maxSize = size;
result = temp[key].nodeId;
} else if (size === maxSize) {
result = Math.min(result, temp[key].nodeId);
}
}
}
return result;
};
class UnionFind {
constructor(count) {
this.count = count;
this.parents = [];
this.sizes = new Array(count).fill(1);
this.init();
}
init() {
for (let i = 0; i < this.count; i++) {
this.parents[i] = i;
}
}
find(node) {
let curNode = node;
while (this.parents[curNode] !== curNode) {
this.parents[curNode] = this.parents[this.parents[curNode]];
curNode = this.parents[curNode];
}
return curNode;
}
union(left, right) {
const leftRoot = this.find(left);
const rightRoot = this.find(right);
if (leftRoot !== rightRoot) {
if (this.sizes[leftRoot] < this.sizes[rightRoot]) {
this.parents[leftRoot] = rightRoot;
this.sizes[rightRoot] += this.sizes[leftRoot];
} else {
this.parents[rightRoot] = leftRoot;
this.sizes[leftRoot] += this.sizes[rightRoot];
}
this.count--;
return true;
}
return false;
}
getSize(node) {
return this.sizes[this.find(node)]
}
}