Skip to content

3310. Remove Methods From Project

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.

Example 1:

Input: n = 4, k = 1, invocations = [[1,2],[0,1],[3,2]]

Output: [0,1,2,3]

Explanation:

img

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.

Example 2:

Input: n = 5, k = 0, invocations = [[1,2],[0,2],[0,1],[3,4]]

Output: [3,4]

Explanation:

img

Methods 0, 1, and 2 are suspicious and they are not directly invoked by any other method. We can remove them.

Example 3:

Input: n = 3, k = 2, invocations = [[1,2],[0,1],[2,0]]

Output: []

Explanation:

img

All methods are suspicious. We can remove them.

Constraints:

  • 1 <= n <= 105
  • 0 <= k <= n - 1
  • 0 <= invocations.length <= 2 * 105
  • invocations[i] == [ai, bi]
  • 0 <= ai, bi <= n - 1
  • ai != bi
  • invocations[i] != invocations[j]

Solution:

class Solution {
    public List<Integer> remainingMethods(int n, int k, int[][] invocations) {
        // Create adjacency lists for the graph (invocations) and reverse graph
        List<List<Integer>> adj = new ArrayList<>();
        List<List<Integer>> revAdj = new ArrayList<>();

        for (int i = 0; i < n; i++) {
            adj.add(new ArrayList<>());
            revAdj.add(new ArrayList<>());
        }

        for (int[] invocation : invocations) {
            int from = invocation[0];
            int to = invocation[1];
            adj.get(from).add(to);
            revAdj.get(to).add(from); // Reverse graph helps check external invocations
        }

        // Step 1: Find all methods suspicious using DFS from method k
        Set<Integer> suspicious = new HashSet<>();
        dfs(k, adj, suspicious);

        // Step 2: Check if any non-suspicious method invokes a suspicious method
        for (int i = 0; i < n; i++) {
            if (!suspicious.contains(i)) {
                // If any non-suspicious method invokes a suspicious one, we can't remove
                for (int invoked : adj.get(i)) {
                    if (suspicious.contains(invoked)) {
                        // If an external method invokes a suspicious method, return all methods
                        List<Integer> result = new ArrayList<>();
                        for (int j = 0; j < n; j++) {
                            result.add(j);
                        }
                        return result;
                    }
                }
            }
        }

        // Step 3: If no external invocations into suspicious methods, return non-suspicious methods
        List<Integer> result = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            if (!suspicious.contains(i)) {
                result.add(i);
            }
        }

        return result;
    }

    // DFS to find all methods reachable from method k (directly or indirectly)
    private void dfs(int node, List<List<Integer>> adj, Set<Integer> visited) {
        if (visited.contains(node)) return;
        visited.add(node);
        for (int neighbor : adj.get(node)) {
            dfs(neighbor, adj, visited);
        }
    }
}