leetcode 第924题 尽量减少恶意软件的传播 python解法
问题分析
最近在看并查集的概念,而leetcode第924题是一道可以用这种方法来解答的(不排除其它的方法)。具体如下:
并查集的概念最主要的就是将相互关联的对象连接起来,作为一个大的集合。而本题就可以将相互连接的节点放到同一个集合中,在这个集合中,只要有一个节点被病毒感染,那么集合中的其它节点也全部被感染。
此外,还有一个对后面的操作很重要的点就是统计每个集合中节点的总个数。在这里有一个公共节点的概念,公共节点指的是集合中所有节点都指向的节点。
为了构造节点集合以及每个节点包含的信息,这里用到了一个辅助数组nums,如下:
其中节点数组代表的是整个网络中所有的节点,而temp数组是对应的节点所指向的位置,比如节点0在temp中对应5,说明这个节点指向节点5(节点5为公共节点),节点3虽然指向节点9,但是节点9也指向节点5,所以节点5是节点3和节点9的公共节点。再看节点5,节点5在temp中对应的数是-7,表明在以节点5为公共节点的这个集合中,总的节点数为7个(0, 1,2, 3, 5, 6,9)。
所以最后可以得到的所有节点的排布为:
图中黑色的节点表示已经被感染,由于题目规定只能删除一个节点,所以我们先来看看如果一个集合中有多个节点(m>=2)被感染会怎样。节点1和节点2在同一个集合而且同时被感染。先假设节点1从感染列表中删除,节点2仍在,在随后的感染过程中节点1还是被节点2感染,这个集合也还是被感染,所以可以有一个结论: 就是同一个集合中如果有多个节点被感染,那么删除这些节点对最后的感染结果没有改变。 所以,如果给的感染列表中的节点都是这种情况的话,就直接返回感染列表中值最小的节点(题目规定)。
然而,上面的这个例子有集合只有一个节点被感染,比如节点4, 8, 12。假如将这些节点从感染列表中删除,那么他们所在的集合在随后都不会被感染,这些就是对我们 “有用” 的节点。
接下来,由于只能删除一个,那么该删除谁呢? 当然是删除所在集合节点数最多的那个节点了!,在这里就是节点4。如何获取感染节点所在集合的总节点数呢?这里用到了前面的一个铺垫,那就是公共节点中有总节点个数的信息。 我们可以找到节点4,8,12各自的公共节点,然后比较节点个数。最后返回节点数最多的那个节点了!
这就是全部的思路了。
源码
class Solution:
def minMalwareSpread(self, graph, initial):
"""
:type graph: List[List[int]]
:type initial: List[int]
:rtype: int
"""
n = len(graph)
initial.sort()
nums = [-1 for i in range(n)]
def find(i):
while nums[i] >= 0:
nums[i] = find(nums[i])
return nums[i]
return i
for i in range(n):
for j in range(i+1, n):
if graph[i][j]:
n1, n2 = find(i), find(j)
if n1 != n2:
nums[n1] += nums[n2]
nums[n2] = n1
bag = {}
for num in initial:
key = find(num)
if key in bag:
bag[key].append(num)
else:
bag[key] = [num]
ret = initial[0]
total = 0
for key, value in bag.items():
if len(value) == 1:
temp = nums[find(key)]
if temp < total:
ret = value[0]
total = temp
return ret