leetcode
leetcode 801 ~ 850
尽量减少恶意软件的传播

尽量减少恶意软件的传播

难度:

标签:

题目描述

代码结果

运行时间: 84 ms, 内存: 19.4 MB


/*
 * 思路:
 * 1. 使用流的API来计算每个节点受到感染的情况。
 * 2. 对于每个初始感染节点,将其移除并计算整个网络的感染节点数。
 * 3. 选择移除后感染节点数最少的节点作为结果,若有多个,选择索引最小的节点。
 */
import java.util.*;
import java.util.stream.*;

public class MinimizeMalwareSpreadStream {
    public int minMalwareSpread(int[][] graph, int[] initial) {
        int n = graph.length;
        Map<Integer, Integer> infectedBy = IntStream.range(0, n).boxed().collect(Collectors.toMap(i -> i, i -> -1));

        Arrays.stream(initial).forEach(node -> {
            if (infectedBy.get(node) == -1) {
                boolean[] visited = new boolean[n];
                dfs(graph, node, node, visited, infectedBy);
            }
        });

        int[] count = new int[n];
        infectedBy.values().stream().filter(v -> v != -1).forEach(v -> count[v]++);

        return Arrays.stream(initial)
                .boxed()
                .min(Comparator.comparingInt((Integer node) -> count[node]).thenComparingInt(node -> node))
                .orElse(-1);
    }

    private void dfs(int[][] graph, int start, int node, boolean[] visited, Map<Integer, Integer> infectedBy) {
        if (visited[node]) return;
        visited[node] = true;
        infectedBy.put(node, start);

        IntStream.range(0, graph.length)
                .filter(i -> graph[node][i] == 1 && !visited[i])
                .forEach(i -> dfs(graph, start, i, visited, infectedBy));
    }
}

解释

方法:

该题解使用了并查集来解决问题。首先根据图构建并查集,将所有连通的节点合并到同一个集合中。然后遍历初始感染节点列表initial,统计每个集合的感染节点数量。如果某个集合只有一个感染节点,就计算删除该节点后能减少感染的节点数,同时更新能减少最多感染节点数的节点索引。最后返回能减少最多感染节点数且索引最小的节点。

时间复杂度:

O(n^2 + m)

空间复杂度:

O(n + m)

代码细节讲解

🦆
在并查集中,如何处理可能存在的多个连通分量,特别是当它们被不同数量的初始感染节点连接时?
在并查集中处理多个连通分量时,首先通过遍历图中的每条边来合并节点,将属于同一个连通分量的节点合并到同一个集合中。对于初始感染节点,我们通过遍历这些节点并使用并查集的`find`方法来确定每个节点所属的集合。然后,我们统计每个集合中初始感染节点的数量。即使集合被不同数量的初始感染节点连接,这种方法也能正确地识别并统计每个集合内的感染节点数量,从而在后续步骤中做出相应的处理决策。
🦆
并查集中合并操作的具体实现(Union 方法)是否考虑了按秩合并,以优化性能?
题解中的并查集的`Union`方法没有明确实现按秩合并。在题解的实现中,当两个节点合并时,简单地将一个集合的根指向另一个集合的根,并更新大小。这种方法可能导致不平衡的树结构,从而影响操作的效率。按秩合并或路径压缩技术可以显著优化并查集操作的性能,特别是在处理大规模数据时,这两种技术能够保持树的高度较低,从而使查找操作更快。
🦆
题解中提到的`统计每个集合的感染节点数量`的方法是否能准确区分不同集合中的感染节点,即如何确保计数的准确性?
题解中通过使用`Counter`字典来统计每个集合的感染节点数量,这种方法依赖于并查集的`find`函数来识别每个初始感染节点所属的集合。只要`find`函数能够准确地返回每个节点的根节点,就可以确保每个初始感染节点被正确归类到其所在的集合。因此,计数的准确性主要取决于并查集的正确实现和维护。
🦆
您提到如果一个集合中只有一个感染节点,删除它将减少该集合的感染节点数。那么如果一个集合中有多个感染节点,删除任何一个是否会影响其它节点的感染状态?
如果一个集合中有多个感染节点,删除其中一个感染节点通常不会影响其他节点的感染状态,因为剩余的感染节点仍然可以维持集合内的感染。在这种情况下,删除一个感染节点不会减少集合的总感染节点数,因为集合中仍然存在其他感染源。因此,在有多个感染节点的集合中,选择删除哪个节点应该基于其他标准,如节点的网络位置或节点的重要性。

相关问题