Skip to content

1192. Critical Connections in a Network 👍

  • Time: $O(n)$
  • Space: $O(n)$
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class Solution {
 public:
  vector<vector<int>> criticalConnections(int n,
                                          vector<vector<int>>& connections) {
    vector<vector<int>> ans;
    vector<vector<int>> graph(n);

    for (const vector<int>& conn : connections) {
      const int u = conn[0];
      const int v = conn[1];
      graph[u].push_back(v);
      graph[v].push_back(u);
    }

    // rank[i] := min node that node i can reach w/ forward edges
    // Initialize w/ NO_RANK = -2 to indicate not visited
    getRank(graph, 0, 0, vector<int>(n, NO_RANK), ans);
    return ans;
  }

 private:
  constexpr static int NO_RANK = -2;

  // The minRank that u can reach w/ forward edges
  int getRank(const vector<vector<int>>& graph, int u, int currRank,
              vector<int>&& rank, vector<vector<int>>& ans) {
    if (rank[u] != NO_RANK)  // The rank is already determined
      return rank[u];

    rank[u] = currRank;
    int minRank = currRank;

    for (const int v : graph[u]) {
      // Visited || parent (that's why NO_RANK = -2 instead of -1)
      if (rank[u] == rank.size() || rank[v] == currRank - 1)
        continue;
      const int nextRank = getRank(graph, v, currRank + 1, move(rank), ans);
      // Path(u, v) is the only way for u go to v
      if (nextRank == currRank + 1)
        ans.push_back({u, v});
      minRank = min(minRank, nextRank);
    }

    rank[u] = rank.size();  // Mark as visited
    return minRank;
  }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class Solution {
  public List<List<Integer>> criticalConnections(int n, List<List<Integer>> connections) {
    List<List<Integer>> ans = new ArrayList<>();
    List<Integer>[] graph = new List[n];

    for (int i = 0; i < n; ++i)
      graph[i] = new ArrayList<>();

    for (List<Integer> conn : connections) {
      final int u = conn.get(0);
      final int v = conn.get(1);
      graph[u].add(v);
      graph[v].add(u);
    }

    // rank[i] := min node that node i can reach w/ forward edges
    // Initialize w/ NO_RANK = -2 to indicate not visited
    int[] rank = new int[n];
    Arrays.fill(rank, NO_RANK);
    getRank(graph, 0, 0, rank, ans);
    return ans;
  }

  private static final int NO_RANK = -2;

  // The minRank that u can reach w/ forward edges
  private int getRank(List<Integer>[] graph, int u, int myRank, int[] rank,
                      List<List<Integer>> ans) {
    if (rank[u] != NO_RANK) // The rank is already been determined
      return rank[u];

    rank[u] = myRank;
    int minRank = myRank;

    for (final int v : graph[u]) {
      // Visited || parent (that's why NO_RANK = -2 instead of -1)
      if (rank[u] == rank.length || rank[v] == myRank - 1)
        continue;
      final int nextRank = getRank(graph, v, myRank + 1, rank, ans);
      // Path(u, v) is the only way for u go to v
      if (nextRank == myRank + 1)
        ans.add(Arrays.asList(u, v));
      minRank = Math.min(minRank, nextRank);
    }

    rank[u] = rank.length; // Mark as visited
    return minRank;
  }
}