You are maintaining a project that has n methods numbered from 0 to n -1.
You are given two integers n and k, and a 2D integer array invocations, where invocations[i] = [ai, bi] indicates that method ai invokes method
bi.
There is a known bug in method k. Method k, along with any method invoked by it, either directly or indirectly , are considered suspicious and we aim to remove them.
A group of methods can only be removed if no method outside the group invokes any methods within it.
Return an array containing all the remaining methods after removing all the
suspicious methods. You may return the answer in any order. If it is not possible to remove all the suspicious methods, none should be removed.
Input: n =4, k =1, invocations =[[1,2],[0,1],[3,2]]Output: [0,1,2,3]Explanation:
Method 2 and method 1 are suspicious, but they are directly invoked by methods 3 and 0, which are not suspicious. We return all elements without removing anything.
Input: n =5, k =0, invocations =[[1,2],[0,2],[0,1],[3,4]]Output: [3,4]Explanation:
Methods 0,1, and 2 are suspicious and they are not directly invoked by any other method. We can remove them.
The core problem is identifying suspicious methods (those reachable from the buggy method k) and determining if they can be safely removed. A suspicious method can only be removed if no non-suspicious method invokes it. We need to build both forward and reverse dependency graphs to check for external dependencies into the suspicious group.
classSolution {
privatefundfs(node: Int, visited: BooleanArray, adj: Array<MutableList<Int>>) {
visited[node] = truefor (neighbor in adj[node]) {
if (!visited[neighbor]) {
dfs(neighbor, visited, adj)
}
}
}
funremainingMethods(n: Int, k: Int, invocations: Array<IntArray>): List<Int> {
// Build forward and reverse adjacency lists
val adj = Array(n) { mutableListOf<Int>() }
val reverseAdj = Array(n) { mutableListOf<Int>() }
for (invocation in invocations) {
adj[invocation[0]].add(invocation[1])
reverseAdj[invocation[1]].add(invocation[0])
}
// Find all suspicious methods (reachable from k)
val suspicious = BooleanArray(n)
dfs(k, suspicious, adj)
// Find all methods that can reach suspicious methods
val canReachSuspicious = BooleanArray(n)
for (i in0 until n) {
if (suspicious[i] && !canReachSuspicious[i]) {
dfs(i, canReachSuspicious, reverseAdj)
}
}
// Check if any non-suspicious method can reach suspicious methods
for (i in0 until n) {
if (canReachSuspicious[i] && !suspicious[i]) {
// External dependency found, return all methods
return (0 until n).toList()
}
}
// No external dependencies, return non-suspicious methods
return (0 until n).filter { !suspicious[it] }
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
defremoveMethods(n, k, invocations):
from collections import deque
g = [[] for _ in range(n)]
for a, b in invocations:
g[a].append(b)
suspicious = [False] * n
q = deque([k])
suspicious[k] =Truewhile q:
u = q.popleft()
for v in g[u]:
ifnot suspicious[v]:
suspicious[v] =True q.append(v)
for a, b in invocations:
ifnot suspicious[a] and suspicious[b]:
return list(range(n))
##### Rust
⏰ Time complexity: O(n + e), where n is the number of methods and e is the number of invocations. Each node and edge is visited at most twice (once in forward DFS to find suspicious methods, once in reverse DFS to check external dependencies).
🧺 Space complexity: O(n + e), for storing the forward and reverse adjacency lists plus the visited arrays.