Minimize Malware Spread II
HardPrompt
You are given a network of n nodes represented as an n x n adjacency matrix graph, where the ith node is directly connected to the jth node if graph[i][j] == 1.
Some nodes initial are initially infected by malware. Whenever two nodes are directly connected, and at least one of those two nodes is infected by malware, both nodes will be infected by malware. This spread of malware will continue until no more nodes can be infected in this manner.
Suppose M(initial) is the final number of nodes infected with malware in the entire network after the spread of malware stops.
We will remove exactly one node from initial, completely removing it and any connections from this node to any other node.
Return the node that, if removed, would minimize M(initial). If multiple nodes could be removed to minimize M(initial), return such a node with the smallest index.
Example 1:
Input: graph = [[1,1,0],[1,1,0],[0,0,1]], initial = [0,1]
Output: 0Example 2:
Input: graph = [[1,1,0],[1,1,1],[0,1,1]], initial = [0,1]
Output: 1Example 3:
Input: graph = [[1,1,0,0],[1,1,1,0],[0,1,1,1],[0,0,1,1]], initial = [0,1]
Output: 1
Constraints:
n == graph.lengthn == graph[i].length2 <= n <= 300graph[i][j]is0or1.graph[i][j] == graph[j][i]graph[i][i] == 11 <= initial.length < n0 <= initial[i] <= n - 1- All the integers in
initialare unique.
Approaches
2 approaches with complexity analysis and trade-offs.
This approach simulates the malware spread for each possible scenario. We iterate through each initially infected node, hypothetically remove it, and then run a full simulation of the malware spread from the remaining infected nodes. The node whose removal results in the fewest total infected nodes is our answer.
Algorithm
- Sort the
initialarray in ascending order. This helps in tie-breaking, as we will find the smallest index first. - Initialize
minInfectedCountto a value larger than any possible outcome (e.g.,n + 1) andresultNodeto the first element of the sortedinitialarray. - Iterate through each
nodeToRemovein the sortedinitialarray. - For each
nodeToRemove, simulate the spread:- Create a set
infectedand a queue for BFS. - Add all nodes from
initial(exceptnodeToRemove) to both theinfectedset and the queue. - Perform a BFS. In each step, for a node
u, explore its neighborsv. Ifvis connected, not thenodeToRemove, and not already infected, add it to theinfectedset and the queue.
- Create a set
- After the BFS completes, the size of the
infectedset is the total number of infected nodes for this scenario. - If this count is less than
minInfectedCount, updateminInfectedCountwith the new count andresultNodetonodeToRemove. - After checking all nodes in
initial, returnresultNode.
Walkthrough
The core idea is to try removing each node from the initial set one by one. For each node u in initial that we consider removing, we define a new set of infected sources, which is initial excluding u. We also treat u as a removed node from the graph, meaning it cannot be visited or spread malware. We then perform a graph traversal (like Breadth-First Search or Depth-First Search) starting from all the new sources. We count the total number of nodes visited during this traversal. This gives us the final number of infected nodes, M, for the scenario where u is removed. We keep track of the node u that leads to the minimum M found so far. To handle ties (multiple nodes giving the same minimum M), we should return the one with the smallest index. A simple way to do this is to sort the initial array first and then iterate. The first node that yields the minimum M will be the answer.
import java.util.*; class Solution { public int minMalwareSpread(int[][] graph, int[] initial) { Arrays.sort(initial); int n = graph.length; int minInfected = n + 1; int resultNode = -1; for (int nodeToRemove : initial) { Set<Integer> infected = new HashSet<>(); Queue<Integer> queue = new LinkedList<>(); for (int startNode : initial) { if (startNode != nodeToRemove) { infected.add(startNode); queue.add(startNode); } } // Using a temporary set to avoid ConcurrentModificationException Set<Integer> currentInfected = new HashSet<>(infected); while (!queue.isEmpty()) { int u = queue.poll(); for (int v = 0; v < n; v++) { if (graph[u][v] == 1 && v != nodeToRemove && !currentInfected.contains(v)) { currentInfected.add(v); queue.add(v); } } } if (currentInfected.size() < minInfected) { minInfected = currentInfected.size(); resultNode = nodeToRemove; } } return resultNode; }}Complexity
Time
O(k * n^2), where `k` is the number of initially infected nodes and `n` is the total number of nodes. For each of the `k` nodes to remove, we perform a BFS on the graph, which takes `O(n^2)` time with an adjacency matrix representation.
Space
O(n) to store the `infected` set and the queue for BFS.
Trade-offs
Pros
Simple to understand and implement.
Directly simulates the process described in the problem.
Cons
Inefficient due to repeated computations. The malware spread simulation is run from scratch for each potential node removal.
Solutions
Solution
class Solution {private int[] p;private int[] size;public int minMalwareSpread(int[][] graph, int[] initial) { int n = graph.length; p = new int[n]; size = new int[n]; for (int i = 0; i < n; ++i) { p[i] = i; size[i] = 1; } boolean[] clean = new boolean[n]; Arrays.fill(clean, true); for (int i : initial) { clean[i] = false; } for (int i = 0; i < n; ++i) { if (!clean[i]) { continue; } for (int j = i + 1; j < n; ++j) { if (clean[j] && graph[i][j] == 1) { union(i, j); } } } int[] cnt = new int[n]; Map<Integer, Set<Integer>> mp = new HashMap<>(); for (int i : initial) { Set<Integer> s = new HashSet<>(); for (int j = 0; j < n; ++j) { if (clean[j] && graph[i][j] == 1) { s.add(find(j)); } } for (int root : s) { cnt[root] += 1; } mp.put(i, s); } int mx = -1; int ans = 0; for (Map.Entry<Integer, Set<Integer>> entry : mp.entrySet()) { int i = entry.getKey(); int t = 0; for (int root : entry.getValue()) { if (cnt[root] == 1) { t += size[root]; } } if (mx < t || (mx == t && i < ans)) { mx = t; ans = i; } } return ans; }private int find(int x) { if (p[x] != x) { p[x] = find(p[x]); } return p[x]; }private void union(int a, int b) { int pa = find(a); int pb = find(b); if (pa != pb) { size[pb] += size[pa]; p[pa] = pb; } }}Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.