comments | difficulty | edit_url | tags | ||||||
---|---|---|---|---|---|---|---|---|---|
true |
困难 |
|
给定一个由 n
个节点组成的网络,用 n x n
个邻接矩阵 graph
表示。在节点网络中,只有当 graph[i][j] = 1
时,节点 i
能够直接连接到另一个节点 j
。
一些节点 initial
最初被恶意软件感染。只要两个节点直接连接,且其中至少一个节点受到恶意软件的感染,那么两个节点都将被恶意软件感染。这种恶意软件的传播将继续,直到没有更多的节点可以被这种方式感染。
假设 M(initial)
是在恶意软件停止传播之后,整个网络中感染恶意软件的最终节点数。
我们可以从 initial
中 删除一个节点,并完全移除该节点以及从该节点到任何其他节点的任何连接。
请返回移除后能够使 M(initial)
最小化的节点。如果有多个节点满足条件,返回索引 最小的节点 。
示例 1:
输入:graph = [[1,1,0],[1,1,0],[0,0,1]], initial = [0,1] 输出:0
示例 2:
输入:graph = [[1,1,0],[1,1,1],[0,1,1]], initial = [0,1] 输出:1
示例 3:
输入:graph = [[1,1,0,0],[1,1,1,0],[0,1,1,1],[0,0,1,1]], initial = [0,1] 输出:1
提示:
n == graph.length
n == graph[i].length
2 <= n <= 300
graph[i][j]
是0
或1
.graph[i][j] == graph[j][i]
graph[i][i] == 1
1 <= initial.length < n
0 <= initial[i] <= n - 1
-
initial
中每个整数都不同
我们可以使用并查集,将所有不在
接下来,我们创建一个哈希表
对于每个初始时被感染的节点
然后,我们用一个变量
遍历所有初始时被感染的节点,对于每个节点
最后返回
时间复杂度
class UnionFind:
__slots__ = "p", "size"
def __init__(self, n: int):
self.p = list(range(n))
self.size = [1] * n
def find(self, x: int) -> int:
if self.p[x] != x:
self.p[x] = self.find(self.p[x])
return self.p[x]
def union(self, a: int, b: int) -> bool:
pa, pb = self.find(a), self.find(b)
if pa == pb:
return False
if self.size[pa] > self.size[pb]:
self.p[pb] = pa
self.size[pa] += self.size[pb]
else:
self.p[pa] = pb
self.size[pb] += self.size[pa]
return True
def get_size(self, root: int) -> int:
return self.size[root]
class Solution:
def minMalwareSpread(self, graph: List[List[int]], initial: List[int]) -> int:
n = len(graph)
s = set(initial)
uf = UnionFind(n)
for i in range(n):
if i not in s:
for j in range(i + 1, n):
graph[i][j] and j not in s and uf.union(i, j)
g = defaultdict(set)
cnt = Counter()
for i in initial:
for j in range(n):
if j not in s and graph[i][j]:
g[i].add(uf.find(j))
for root in g[i]:
cnt[root] += 1
ans, mx = 0, -1
for i in initial:
t = sum(uf.get_size(root) for root in g[i] if cnt[root] == 1)
if t > mx or (t == mx and i < ans):
ans, mx = i, t
return ans
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;
}
}
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), pb = find(b);
if (pa == pb) {
return false;
}
if (size[pa] > size[pb]) {
p[pb] = pa;
size[pa] += size[pb];
} else {
p[pa] = pb;
size[pb] += size[pa];
}
return true;
}
public int size(int root) {
return size[root];
}
}
class Solution {
public int minMalwareSpread(int[][] graph, int[] initial) {
int n = graph.length;
boolean[] s = new boolean[n];
for (int i : initial) {
s[i] = true;
}
UnionFind uf = new UnionFind(n);
for (int i = 0; i < n; ++i) {
if (!s[i]) {
for (int j = i + 1; j < n; ++j) {
if (graph[i][j] == 1 && !s[j]) {
uf.union(i, j);
}
}
}
}
Set<Integer>[] g = new Set[n];
Arrays.setAll(g, k -> new HashSet<>());
int[] cnt = new int[n];
for (int i : initial) {
for (int j = 0; j < n; ++j) {
if (!s[j] && graph[i][j] == 1) {
g[i].add(uf.find(j));
}
}
for (int root : g[i]) {
++cnt[root];
}
}
int ans = 0, mx = -1;
for (int i : initial) {
int t = 0;
for (int root : g[i]) {
if (cnt[root] == 1) {
t += uf.size(root);
}
}
if (t > mx || (t == mx && i < ans)) {
ans = i;
mx = t;
}
}
return ans;
}
}
class UnionFind {
public:
UnionFind(int n) {
p = vector<int>(n);
size = vector<int>(n, 1);
iota(p.begin(), p.end(), 0);
}
bool unite(int a, int b) {
int pa = find(a), pb = find(b);
if (pa == pb) {
return false;
}
if (size[pa] > size[pb]) {
p[pb] = pa;
size[pa] += size[pb];
} else {
p[pa] = pb;
size[pb] += size[pa];
}
return true;
}
int find(int x) {
if (p[x] != x) {
p[x] = find(p[x]);
}
return p[x];
}
int getSize(int root) {
return size[root];
}
private:
vector<int> p, size;
};
class Solution {
public:
int minMalwareSpread(vector<vector<int>>& graph, vector<int>& initial) {
int n = graph.size();
bool s[n];
memset(s, false, sizeof(s));
for (int i : initial) {
s[i] = true;
}
UnionFind uf(n);
for (int i = 0; i < n; ++i) {
if (!s[i]) {
for (int j = i + 1; j < n; ++j) {
if (graph[i][j] && !s[j]) {
uf.unite(i, j);
}
}
}
}
unordered_set<int> g[n];
int cnt[n];
memset(cnt, 0, sizeof(cnt));
for (int i : initial) {
for (int j = 0; j < n; ++j) {
if (!s[j] && graph[i][j]) {
g[i].insert(uf.find(j));
}
}
for (int root : g[i]) {
++cnt[root];
}
}
int ans = 0, mx = -1;
for (int i : initial) {
int t = 0;
for (int root : g[i]) {
if (cnt[root] == 1) {
t += uf.getSize(root);
}
}
if (t > mx || (t == mx && i < ans)) {
ans = i;
mx = t;
}
}
return ans;
}
};
type unionFind struct {
p, size []int
}
func newUnionFind(n int) *unionFind {
p := make([]int, n)
size := make([]int, n)
for i := range p {
p[i] = i
size[i] = 1
}
return &unionFind{p, size}
}
func (uf *unionFind) find(x int) int {
if uf.p[x] != x {
uf.p[x] = uf.find(uf.p[x])
}
return uf.p[x]
}
func (uf *unionFind) union(a, b int) bool {
pa, pb := uf.find(a), uf.find(b)
if pa == pb {
return false
}
if uf.size[pa] > uf.size[pb] {
uf.p[pb] = pa
uf.size[pa] += uf.size[pb]
} else {
uf.p[pa] = pb
uf.size[pb] += uf.size[pa]
}
return true
}
func (uf *unionFind) getSize(root int) int {
return uf.size[root]
}
func minMalwareSpread(graph [][]int, initial []int) int {
n := len(graph)
s := make([]bool, n)
for _, i := range initial {
s[i] = true
}
uf := newUnionFind(n)
for i := range graph {
if !s[i] {
for j := i + 1; j < n; j++ {
if graph[i][j] == 1 && !s[j] {
uf.union(i, j)
}
}
}
}
g := make([]map[int]bool, n)
for _, i := range initial {
g[i] = map[int]bool{}
}
cnt := make([]int, n)
for _, i := range initial {
for j := 0; j < n; j++ {
if !s[j] && graph[i][j] == 1 {
g[i][uf.find(j)] = true
}
}
for root := range g[i] {
cnt[root]++
}
}
ans, mx := 0, -1
for _, i := range initial {
t := 0
for root := range g[i] {
if cnt[root] == 1 {
t += uf.getSize(root)
}
}
if t > mx || t == mx && i < ans {
ans, mx = i, t
}
}
return ans
}
class UnionFind {
p: number[];
size: number[];
constructor(n: number) {
this.p = Array(n)
.fill(0)
.map((_, i) => i);
this.size = Array(n).fill(1);
}
find(x: number): number {
if (this.p[x] !== x) {
this.p[x] = this.find(this.p[x]);
}
return this.p[x];
}
union(a: number, b: number): boolean {
const [pa, pb] = [this.find(a), this.find(b)];
if (pa === pb) {
return false;
}
if (this.size[pa] > this.size[pb]) {
this.p[pb] = pa;
this.size[pa] += this.size[pb];
} else {
this.p[pa] = pb;
this.size[pb] += this.size[pa];
}
return true;
}
getSize(root: number): number {
return this.size[root];
}
}
function minMalwareSpread(graph: number[][], initial: number[]): number {
const n = graph.length;
const s = new Set(initial);
const uf = new UnionFind(n);
for (let i = 0; i < n; ++i) {
if (!s.has(i)) {
for (let j = i + 1; j < n; ++j) {
if (graph[i][j] && !s.has(j)) {
uf.union(i, j);
}
}
}
}
const g: Set<number>[] = Array.from({ length: n }, () => new Set());
const cnt: number[] = Array(n).fill(0);
for (const i of initial) {
for (let j = 0; j < n; ++j) {
if (graph[i][j] && !s.has(j)) {
g[i].add(uf.find(j));
}
}
for (const root of g[i]) {
++cnt[root];
}
}
let ans = 0;
let mx = -1;
for (const i of initial) {
let t = 0;
for (const root of g[i]) {
if (cnt[root] === 1) {
t += uf.getSize(root);
}
}
if (t > mx || (t === mx && i < ans)) {
[ans, mx] = [i, t];
}
}
return ans;
}