|
| 1 | +/** |
| 2 | + * 1489. Find Critical and Pseudo-Critical Edges in Minimum Spanning Tree |
| 3 | + * https://leetcode.com/problems/find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree/ |
| 4 | + * Difficulty: Hard |
| 5 | + * |
| 6 | + * Given a weighted undirected connected graph with n vertices numbered from 0 to n - 1, and an |
| 7 | + * array edges where edges[i] = [ai, bi, weighti] represents a bidirectional and weighted edge |
| 8 | + * between nodes ai and bi. A minimum spanning tree (MST) is a subset of the graph's edges that |
| 9 | + * connects all vertices without cycles and with the minimum possible total edge weight. |
| 10 | + * |
| 11 | + * Find all the critical and pseudo-critical edges in the given graph's minimum spanning tree |
| 12 | + * (MST). An MST edge whose deletion from the graph would cause the MST weight to increase is |
| 13 | + * called a critical edge. On the other hand, a pseudo-critical edge is that which can appear |
| 14 | + * in some MSTs but not all. |
| 15 | + * |
| 16 | + * Note that you can return the indices of the edges in any order. |
| 17 | + */ |
| 18 | + |
| 19 | +/** |
| 20 | + * @param {number} n |
| 21 | + * @param {number[][]} edges |
| 22 | + * @return {number[][]} |
| 23 | + */ |
| 24 | +var findCriticalAndPseudoCriticalEdges = function(n, edges) { |
| 25 | + const indexedEdges = edges.map((edge, i) => [...edge, i]); |
| 26 | + indexedEdges.sort((a, b) => a[2] - b[2]); |
| 27 | + |
| 28 | + const minWeight = getMSTWeight(); |
| 29 | + const critical = []; |
| 30 | + const pseudoCritical = []; |
| 31 | + |
| 32 | + for (let i = 0; i < edges.length; i++) { |
| 33 | + if (getMSTWeight(i) > minWeight) { |
| 34 | + critical.push(indexedEdges[i][3]); |
| 35 | + } else if (getMSTWeight(-1, i) === minWeight) { |
| 36 | + pseudoCritical.push(indexedEdges[i][3]); |
| 37 | + } |
| 38 | + } |
| 39 | + |
| 40 | + return [critical, pseudoCritical]; |
| 41 | + |
| 42 | + function findParent(parents, x) { |
| 43 | + if (parents[x] !== x) parents[x] = findParent(parents, parents[x]); |
| 44 | + return parents[x]; |
| 45 | + } |
| 46 | + |
| 47 | + function union(parents, ranks, x, y) { |
| 48 | + const px = findParent(parents, x); |
| 49 | + const py = findParent(parents, y); |
| 50 | + if (px === py) return false; |
| 51 | + if (ranks[px] < ranks[py]) { |
| 52 | + parents[px] = py; |
| 53 | + } else if (ranks[px] > ranks[py]) { |
| 54 | + parents[py] = px; |
| 55 | + } else { |
| 56 | + parents[py] = px; |
| 57 | + ranks[px]++; |
| 58 | + } |
| 59 | + return true; |
| 60 | + } |
| 61 | + |
| 62 | + function getMSTWeight(exclude = -1, include = -1) { |
| 63 | + const parents = Array.from({ length: n }, (_, i) => i); |
| 64 | + const ranks = new Array(n).fill(0); |
| 65 | + let weight = 0; |
| 66 | + let edgesUsed = 0; |
| 67 | + |
| 68 | + if (include !== -1) { |
| 69 | + const [u, v, w] = indexedEdges[include]; |
| 70 | + if (union(parents, ranks, u, v)) { |
| 71 | + weight += w; |
| 72 | + edgesUsed++; |
| 73 | + } |
| 74 | + } |
| 75 | + |
| 76 | + for (let i = 0; i < indexedEdges.length; i++) { |
| 77 | + if (i === exclude || i === include) continue; |
| 78 | + const [u, v, w] = indexedEdges[i]; |
| 79 | + if (union(parents, ranks, u, v)) { |
| 80 | + weight += w; |
| 81 | + edgesUsed++; |
| 82 | + } |
| 83 | + } |
| 84 | + |
| 85 | + return edgesUsed === n - 1 ? weight : Infinity; |
| 86 | + } |
| 87 | +}; |
0 commit comments