Bridges in Graph Tarjan's Algorithm in DSA Javascript - Time & Space Complexity
We want to understand how the time needed to find bridges in a graph grows as the graph gets bigger.
Specifically, how does Tarjan's algorithm perform when checking all connections?
Analyze the time complexity of the following code snippet.
function findBridges(graph) {
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);
let time = 0;
const bridges = [];
function dfs(u, parent) {
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]);
}
}
}
for (let i = 0; i < n; i++) {
if (!visited[i]) dfs(i, -1);
}
return bridges;
}
This code finds all bridges (critical connections) in an undirected graph using depth-first search and tracking discovery and low times.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Depth-first search (DFS) visits each node and explores all its edges.
- How many times: Each node is visited once, and each edge is checked once during DFS.
As the graph grows with more nodes and edges, the algorithm visits each node once and checks each edge once.
| Input Size (n nodes, m edges) | Approx. Operations |
|---|---|
| 10 nodes, 15 edges | About 10 visits + 15 edge checks = 25 operations |
| 100 nodes, 200 edges | About 100 visits + 200 edge checks = 300 operations |
| 1000 nodes, 5000 edges | About 1000 visits + 5000 edge checks = 6000 operations |
Pattern observation: The operations grow roughly in proportion to the sum of nodes and edges.
Time Complexity: O(n + m)
This means the time grows linearly with the number of nodes plus the number of edges in the graph.
[X] Wrong: "The algorithm checks every possible pair of nodes, so it must be O(n²)."
[OK] Correct: The algorithm only visits each node once and explores edges directly connected to it, not all pairs. So it depends on actual edges, not all pairs.
Understanding this linear time complexity helps you explain how efficient graph algorithms work in real problems, showing you can handle large data without slowdowns.
"What if the graph was directed instead of undirected? How would the time complexity change?"
Practice
Solution
Step 1: Understand the definition of a bridge
A bridge is an edge that, when removed, increases the number of connected components in a graph.Step 2: Relate Tarjan's algorithm to bridges
Tarjan's algorithm efficiently finds such edges by using DFS and tracking discovery and low times.Final Answer:
To identify edges that, if removed, increase the number of connected components -> Option BQuick Check:
Bridges = edges increasing components when removed [OK]
- Confusing bridges with cycles
- Thinking it finds shortest paths
- Assuming it counts nodes
Solution
Step 1: Understand array initialization in JavaScript
Using new Array(n).fill(value) correctly fills all elements with the given value.Step 2: Check each option
A: const disc = new Array(n).fill(-1); correctly creates an array of length n filled with -1. B: const disc = Array(n).map(() => 0); fills with 0 instead of -1. C: const disc = new Array(n).map(0); passes non-function to map, causing TypeError. D: const disc = Array.fill(n, -1); uses incorrect syntax (no static Array.fill).Final Answer:
const disc = new Array(n).fill(-1); -> Option AQuick Check:
Use fill() to initialize arrays [OK]
- Initializing with 0 instead of -1
- Passing non-function to map
- Wrong syntax for Array.fill
const graph = [[1],[0,2,3],[1,0],[1]]; // Assume Tarjan's algorithm is correctly implemented and called // Output bridges are printed as pairs of nodes
Solution
Step 1: Analyze the graph structure
The graph has a triangle between nodes 0,1,2 and a single edge from 1 to 3.Step 2: Identify bridges
The triangle edges are part of a cycle, so none are bridges. The edge [1,3] connects node 3 alone, so removing it increases components.Final Answer:
[[1,3]] -> Option DQuick Check:
Only edge to isolated node is bridge [OK]
- Marking cycle edges as bridges
- Ignoring isolated node connections
- Confusing node indices
function dfs(u, parent) {
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 variable initialization
The code uses 'visited' array but does not show its initialization, which is necessary before DFS.Step 2: Verify other parts
The condition 'low[v] > disc[u]' is correct for bridges. The time variable is incremented properly. The else if condition correctly checks 'v !== parent'.Final Answer:
The 'visited' array is not initialized -> Option AQuick Check:
Initialize visited before DFS [OK]
- Changing correct bridge condition
- Misunderstanding parent check
- Forgetting to initialize arrays
Solution
Step 1: Analyze the graph structure
Nodes 0,1,2 form a cycle, so edges among them are not bridges. Edges [1,3] and [3,4] connect nodes outside the cycle.Step 2: Identify bridges
Removing [1,3] or [3,4] increases connected components, so these are bridges.Final Answer:
[[1,3],[3,4]] -> Option CQuick Check:
Edges connecting cycle to outside are bridges [OK]
- Marking cycle edges as bridges
- Ignoring edges connecting outside nodes
- Confusing node indices
Ready to prove it?
Pass the test and this pattern moves unknown
