0924. 尽量减少恶意软件的传播
大约 3 分钟
---
0924. 尽量减少恶意软件的传播
- 标签:深度优先搜索、广度优先搜索、并查集、图、数组、哈希表
- 难度:困难
题目链接
题目大意
描述:
给定一个由 个节点组成的网络,用 个邻接矩阵图 表示。在节点网络中,当 时,表示节点 能够直接连接到另一个节点 。
一些节点 最初被恶意软件感染。只要两个节点直接连接,且其中至少一个节点受到恶意软件的感染,那么两个节点都将被恶意软件感染。这种恶意软件的传播将继续,直到没有更多的节点可以被这种方式感染。
假设 是在恶意软件停止传播之后,整个网络中感染恶意软件的最终节点数。
要求:
如果从 中移除某一节点能够最小化 ,返回该节点。如果有多个节点满足条件,就返回索引最小的节点。
说明:
- 注意:如果某个节点已从受感染节点的列表 中删除,它以后仍有可能因恶意软件传播而受到感染。
- 。
- 。
- 。
- 或 。
- 。
- 。
- 。
- 。
- 中所有整数均不重复。
示例:
- 示例 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解题思路
思路 1:并查集
这道题的关键是找到删除哪个初始感染节点能最大程度减少感染范围。
- 构建连通分量:使用并查集将所有节点连接起来,形成连通分量。
- 统计影响:对于每个连通分量,统计其中包含的初始感染节点数量和连通分量大小。
- 选择最优节点:
- 如果一个连通分量只包含一个初始感染节点,删除该节点可以拯救整个连通分量
- 如果一个连通分量包含多个初始感染节点,删除任何一个都无法拯救它
- 选择能拯救最多节点的初始感染节点,如果有多个,选择索引最小的
思路 1:代码
class Solution:
def minMalwareSpread(self, graph: List[List[int]], initial: List[int]) -> int:
n = len(graph)
initial_set = set(initial)
# 并查集
parent = list(range(n))
def find(x):
if parent[x] != x:
parent[x] = find(parent[x])
return parent[x]
def union(x, y):
px, py = find(x), find(y)
if px != py:
parent[px] = py
# 将所有相连的节点连接起来
for i in range(n):
for j in range(i + 1, n):
if graph[i][j] == 1:
union(i, j)
# 统计每个连通分量的大小和包含的初始感染节点
component_size = collections.defaultdict(int)
component_malware = collections.defaultdict(list)
for i in range(n):
root = find(i)
component_size[root] += 1
if i in initial_set:
component_malware[root].append(i)
# 统计删除每个初始感染节点能拯救的节点数
saved = collections.defaultdict(int)
for root, malware_list in component_malware.items():
# 只有一个初始感染节点时,删除它可以拯救整个连通分量(除了它自己)
if len(malware_list) == 1:
m = malware_list[0]
saved[m] = component_size[root]
# 选择能拯救最多节点的初始感染节点
initial.sort()
max_saved = max(saved.values()) if saved else 0
for node in initial:
if saved[node] == max_saved:
return node
return initial[0]思路 1:复杂度分析
- 时间复杂度:,其中 是节点数量。需要遍历邻接矩阵构建并查集。
- 空间复杂度:,需要使用并查集和哈希表存储信息。