-
-
Notifications
You must be signed in to change notification settings - Fork 40
/
Copy path0924-minimize-malware-spread.py
100 lines (85 loc) · 2.97 KB
/
0924-minimize-malware-spread.py
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# time complexity: O(n^2)
# space complexity: O(n)
import collections
from typing import List
class Solution:
def minMalwareSpread(self, graph: List[List[int]], initial: List[int]) -> int:
N = len(graph)
colors = {}
c = 0
def dfs(node, color):
colors[node] = color
for nei, adj in enumerate(graph[node]):
if adj and nei not in colors:
dfs(nei, color)
for node in range(N):
if node not in colors:
dfs(node, c)
c += 1
size = collections.Counter(colors.values())
colorCount = collections.Counter()
for node in initial:
colorCount[colors[node]] += 1
ans = float('inf')
for x in initial:
c = colors[x]
if colorCount[c] == 1:
if ans == float('inf'):
ans = x
elif size[c] > size[colors[ans]]:
ans = x
elif size[c] == size[colors[ans]] and x < ans:
ans = x
return ans if ans < float('inf') else min(initial)
# time complexity: O(n^2)
# space complexity: O(n)
class UnionFind:
def __init__(self, n):
self.parents = [num for num in range(n + 1)]
self.ranks = [1 for _ in range(n)]
def find(self, num):
if self.parents[num] != num:
self.parents[num] = self.find(self.parents[num])
return self.parents[num]
def union(self, x, y):
rootX = self.find(x)
rootY = self.find(y)
if rootX == rootY:
return
small, big = sorted([rootX, rootY], key=lambda z: self.ranks[z])
self.parents[small] = big
self.ranks[big] += self.ranks[small]
class Solution:
def minMalwareSpread(self, graph: List[List[int]], initial: List[int]) -> int:
ROW = len(graph)
COL = len(graph[0])
uf = UnionFind(ROW)
for r in range(ROW):
for c in range(COL):
if graph[r][c]:
uf.union(r, c)
infected = collections.defaultdict(int)
for num in initial:
infected[uf.find(num)] += 1
maxSize = 0
candidateNode = min(initial)
for num in initial:
infectionCount = infected[uf.find(num)]
componentSize = uf.ranks[uf.find(num)]
if infectionCount != 1:
continue
if componentSize > maxSize:
maxSize = componentSize
candidateNode = num
elif componentSize == maxSize and num < candidateNode:
candidateNode = num
return candidateNode
graph = [[1, 1, 0], [1, 1, 0], [0, 0, 1]]
initial = [0, 1]
print(Solution().minMalwareSpread(graph, initial))
graph = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
initial = [0, 2]
print(Solution().minMalwareSpread(graph, initial))
graph = [[1, 1, 1], [1, 1, 1], [1, 1, 1]]
initial = [1, 2]
print(Solution().minMalwareSpread(graph, initial))