Bridges in Graph Tarjan's Algorithm in DSA Typescript - Time & Space Complexity
We want to know how the time needed to find bridges in a graph grows as the graph gets bigger.
Specifically, how the algorithm's steps increase with more nodes and edges.
Analyze the time complexity of the following code snippet.
function findBridges(graph: number[][]): [number, number][] {
const n = graph.length;
const visited = new Array(n).fill(false);
const disc = new Array(n).fill(-1);
const low = new Array(n).fill(-1);
const bridges: [number, number][] = [];
let time = 0;
function dfs(u: number, parent: number) {
visited[u] = true;
disc[u] = low[u] = time++;
for (const v of graph[u]) {
if (v === parent) continue;
if (!visited[v]) {
dfs(v, u);
low[u] = Math.min(low[u], low[v]);
if (low[v] > disc[u]) bridges.push([u, v]);
} else {
low[u] = Math.min(low[u], disc[v]);
}
}
}
for (let i = 0; i < n; i++) {
if (!visited[i]) dfs(i, -1);
}
return bridges;
}
This code finds all bridges (edges that if removed increase graph parts) using DFS and tracking discovery times.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Depth-first search (DFS) visits each node and its edges once.
- How many times: Each node is visited once, and each edge is checked once.
As the number of nodes and edges grow, the algorithm checks each node and edge once.
| Input Size (n nodes, m edges) | Approx. Operations |
|---|---|
| 10 nodes, 15 edges | About 25 operations (visiting nodes + edges) |
| 100 nodes, 200 edges | About 300 operations |
| 1000 nodes, 3000 edges | About 4000 operations |
Pattern observation: Operations grow roughly in proportion to nodes plus edges.
Time Complexity: O(n + m)
This means the time grows linearly with the number of nodes and edges in the graph.
[X] Wrong: "The algorithm checks every possible path, so it must be exponential."
[OK] Correct: The DFS visits each node and edge only once, not all paths, so it runs efficiently in linear time.
Understanding this linear time complexity helps you explain how graph algorithms handle large data efficiently.
"What if the graph was represented as an adjacency matrix instead of adjacency lists? How would the time complexity change?"
Practice
Solution
Step 1: Understand what a bridge is in a graph
A bridge is an edge that, when removed, increases the number of connected components in the graph.Step 2: Identify Tarjan's algorithm goal
Tarjan's algorithm is used to find such edges efficiently by using DFS and tracking discovery and low times.Final Answer:
To find edges that, if removed, increase the number of connected components -> Option DQuick Check:
Bridges = edges increasing components when removed [OK]
- Confusing bridges with cycles
- Thinking it finds shortest paths
- Mixing with topological sorting
Solution
Step 1: Understand array declaration with initial values in TypeScript
To create an array of numbers with size n and initialize all values to -1, use new Array(n).fill(-1).Step 2: Check type correctness
TypeScript syntax requires disc to be number[] for an array of numbers.Final Answer:
let disc: number[] = new Array(n).fill(-1); -> Option CQuick Check:
Array<number> with fill(-1) = correct initialization [OK]
- Using wrong type annotation
- Not initializing array values
- Filling with string instead of number
const graph = [[1, 2], [0, 2], [0, 1, 3], [2, 4], [3]]; // Edges: 0-1, 0-2, 1-2, 2-3, 3-4 // Find bridges const bridges = findBridges(graph); console.log(bridges);
Solution
Step 1: Analyze the graph edges and connectivity
The graph edges are 0-1, 0-2, 1-2 forming a triangle, and 2-3, 3-4 forming a chain. The triangle edges are not bridges because removing one does not disconnect the graph.Step 2: Identify bridges
Edges 2-3 and 3-4 are bridges because removing either disconnects node 4 or node 3 from the rest.Final Answer:
[[2, 3], [3, 4]] -> Option AQuick Check:
Bridges disconnect graph = [[2,3],[3,4]] [OK]
- Including edges inside cycles as bridges
- Missing chain edges as bridges
- Confusing node indices
function dfs(u: number, parent: number) {
visited[u] = true;
disc[u] = low[u] = time++;
for (const v of graph[u]) {
if (!visited[v]) {
dfs(v, u);
low[u] = Math.min(low[u], low[v]);
if (low[v] > disc[u]) {
bridges.push([u, v]);
}
} else if (v !== parent) {
low[u] = Math.min(low[u], disc[v]);
}
}
}Solution
Step 1: Check initialization of visited array
The code uses 'visited[u]' but does not show initialization. Without initializing, visited may be undefined causing runtime errors.Step 2: Verify other parts
The condition 'low[v] > disc[u]' is correct for bridges. The parent check is present. The time increment is correct.Final Answer:
The 'visited' array is not initialized before DFS -> Option BQuick Check:
Uninitialized visited array causes errors [OK]
- Changing correct bridge condition
- Ignoring visited initialization
- Removing parent check
Solution
Step 1: Analyze graph structure
Edges 0-1, 1-2, 2-0 form a triangle (cycle). Edges 3-4, 4-5, 5-3 form another cycle. Edge 1-3 connects these two cycles.Step 2: Identify bridges
Only edge 1-3 is a bridge because removing it disconnects the two cycles. Other edges are part of cycles and not bridges.Final Answer:
[[1, 3]] -> Option AQuick Check:
Bridge connects two cycles = [[1, 3]] [OK]
- Marking cycle edges as bridges
- Missing the connecting bridge edge
- Confusing node pairs
Ready to prove it?
Pass the test and this pattern moves unknown
