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