#1489

Find Critical and Pseudo-Critical Edges in Minimum Spanning Tree

Hard
Union-FindGraph TheorySortingMinimum Spanning TreeStrongly Connected ComponentUnion-FindGraph TheoryMinimum Spanning Tree
LeetCode ↗

Approaches

Brute ForceOptimal
Complexity Comparison
Brute ForceOptimal Solution
Time
O(2^E * E log E)
O(E log E)
Space
O(E)
O(E)
💡

Intuition

Time O(E log E)Space O(E)

Using Kruskal's algorithm with a union-find data structure allows us to efficiently determine the minimum spanning tree and identify critical and pseudo-critical edges without generating all subsets.

⚙️

Algorithm

4 steps
  1. 1Step 1: Sort the edges by weight.
  2. 2Step 2: Use union-find to construct the minimum spanning tree (MST) and calculate its weight.
  3. 3Step 3: For each edge, check if removing it increases the MST weight (critical edge).
  4. 4Step 4: For each edge, check if including it in the MST results in the same weight (pseudo-critical edge).
solution.py49 lines
1# Full working Python code
2class UnionFind:
3    def __init__(self, n):
4        self.parent = list(range(n))
5        self.rank = [1] * n
6    def find(self, x):
7        if self.parent[x] != x:
8            self.parent[x] = self.find(self.parent[x])
9        return self.parent[x]
10    def union(self, x, y):
11        rootX, rootY = self.find(x), self.find(y)
12        if rootX != rootY:
13            if self.rank[rootX] > self.rank[rootY]:
14                self.parent[rootY] = rootX
15            elif self.rank[rootX] < self.rank[rootY]:
16                self.parent[rootX] = rootY
17            else:
18                self.parent[rootY] = rootX
19                self.rank[rootX] += 1
20
21def kruskal(n, edges, skip_index=-1, include_index=-1):
22    uf = UnionFind(n)
23    total_weight = 0
24    edge_count = 0
25    if include_index != -1:
26        u, v, w, _ = edges[include_index]
27        uf.union(u, v)
28        total_weight += w
29        edge_count += 1
30    for i, (u, v, w, _) in enumerate(edges):
31        if i == skip_index:
32            continue
33        if uf.find(u) != uf.find(v):
34            uf.union(u, v)
35            total_weight += w
36            edge_count += 1
37    return total_weight if edge_count == n - 1 else float('inf')
38
39def findCriticalAndPseudoCriticalEdges(n, edges):
40    edges = [[u, v, w, i] for i, (u, v, w) in enumerate(edges)]
41    edges.sort(key=lambda x: x[2])
42    mst_weight = kruskal(n, edges)
43    critical, pseudo_critical = [], []
44    for i in range(len(edges)):
45        if kruskal(n, edges, skip_index=i) > mst_weight:
46            critical.append(edges[i][3])
47        elif kruskal(n, edges, include_index=i) == mst_weight:
48            pseudo_critical.append(edges[i][3])
49    return [critical, pseudo_critical]

Complexity note: The complexity comes from sorting the edges (O(E log E)) and performing union-find operations, which are nearly constant time due to path compression.

  • 1Understanding the difference between critical and pseudo-critical edges is essential for solving this problem effectively.
  • 2Using union-find efficiently helps manage connected components and detect cycles while building the MST.

Solutions and explanations are original Tejav content. Problem titles © LeetCode — use the LeetCode button above for the full problem statement.