Imagine you're a network engineer designing optimal routes through a communication network. You have an undirected weighted graph representing n network nodes (numbered from 0 to n-1) connected by m communication links.
Each link is represented as edges[i] = [ai, bi, wi], meaning there's a connection between nodes ai and bi with transmission cost wi.
Your mission: Find all the critical communication links that are part of at least one shortest path from the source node 0 to the destination node n-1.
Goal: Return a boolean array answer where answer[i] is true if edge edges[i] lies on at least one shortest path from node 0 to node n-1.
Note: The network might be disconnected, so some paths may not exist!
π‘ Note:The shortest path from 0 to 3 has length 9 and follows route 0β1β2β3 with cost 4+2+3=9. The alternative route 0β4β3 has cost 5+6=11, so edges involving node 4 are not part of any shortest path.
π‘ Note:There are two shortest paths from 0 to 3, both with length 2: path 0β1β3 and path 0β2β3. Since every edge participates in at least one shortest path, all edges are marked as true.
example_3.py β Disconnected Graph
$Input:n = 4, edges = [[0,1,1],[2,3,1]]
βΊOutput:[false, false]
π‘ Note:Node 0 and node 3 are in different connected components, so no path exists between them. Therefore, no edge can be part of a shortest path from 0 to 3.
Constraints
2 β€ n β€ 104
0 β€ edges.length β€ min(104, n * (n - 1) / 2)
edges[i].length == 3
0 β€ ai, bi β€ n - 1
ai β bi
1 β€ wi β€ 106
No multi-edges or self-loops
The graph may be disconnected
Visualization
Tap to expand
Understanding the Visualization
1
π Forward Scan
Calculate shortest distances from source to all nodes using Dijkstra's algorithm
2
π― Backward Scan
Calculate shortest distances from destination back to all nodes
3
π Edge Analysis
For each network link, check if it's part of an optimal route using the distance formula
4
β Critical Path Identification
Mark all links that contribute to at least one shortest path
Key Takeaway
π― Key Insight: An edge is critical if it lies on at least one shortest path. We can determine this efficiently by checking if the sum of distances (sourceβedge_start + edge_weight + edge_endβdestination) equals the overall shortest path length.
The optimal solution uses Two-Pass Dijkstra algorithm. We run Dijkstra's algorithm once from the source node and once from the destination node to get shortest distances. Then, for each edge, we check if it lies on a shortest path using the formula: dist_from_source[u] + edge_weight + dist_to_dest[v] == shortest_path_length. Time complexity: O((V + E) log V), Space complexity: O(V + E).
Common Approaches
Approach
Time
Space
Notes
β
Brute Force (All Paths Enumeration)
O(V! * E)
O(V * P)
Find all paths from source to destination and identify which edges appear in shortest ones
Two-Pass Dijkstra (Optimal)
O((V + E) log V)
O(V + E)
Run Dijkstra from both source and destination, then check each edge for shortest path inclusion
Brute Force (All Paths Enumeration) β Algorithm Steps
Use DFS to find all possible paths from node 0 to node n-1
Calculate the length of each path and find the minimum
Filter paths that have the minimum length (shortest paths)
For each edge, check if it appears in any of the shortest paths
Return boolean array indicating which edges are part of shortest paths
Visualization
Tap to expand
Step-by-Step Walkthrough
1
Build Graph
Create adjacency list from edge array
2
Explore All Paths
Use DFS to find every path from source to destination
3
Find Minimum Cost
Calculate cost of each path and identify shortest ones
4
Mark Critical Edges
Mark edges that appear in any shortest path
Code -
solution.c β C
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>
typedef struct {
int cost;
int* edges;
int edgeCount;
} Path;
typedef struct {
int neighbor;
int weight;
int edgeIdx;
} Edge;
typedef struct {
Edge* edges;
int count;
int capacity;
} AdjList;
Path* allPaths;
int pathCount;
int pathCapacity;
void dfs(int node, int target, int cost, int* usedEdges, int edgeCount,
bool* visited, AdjList* graph, int n) {
if (node == target) {
if (pathCount >= pathCapacity) {
pathCapacity *= 2;
allPaths = realloc(allPaths, pathCapacity * sizeof(Path));
}
allPaths[pathCount].cost = cost;
allPaths[pathCount].edges = malloc(edgeCount * sizeof(int));
for (int i = 0; i < edgeCount; i++) {
allPaths[pathCount].edges[i] = usedEdges[i];
}
allPaths[pathCount].edgeCount = edgeCount;
pathCount++;
return;
}
for (int i = 0; i < graph[node].count; i++) {
Edge edge = graph[node].edges[i];
if (!visited[edge.neighbor]) {
visited[edge.neighbor] = true;
usedEdges[edgeCount] = edge.edgeIdx;
dfs(edge.neighbor, target, cost + edge.weight, usedEdges, edgeCount + 1,
visited, graph, n);
visited[edge.neighbor] = false;
}
}
}
bool* findEdgesInShortestPaths(int n, int** edges, int edgesSize, int* edgesColSize) {
bool* result = calloc(edgesSize, sizeof(bool));
if (n <= 1) return result;
AdjList* graph = malloc(n * sizeof(AdjList));
for (int i = 0; i < n; i++) {
graph[i].edges = NULL;
graph[i].count = 0;
graph[i].capacity = 0;
}
for (int i = 0; i < edgesSize; i++) {
int u = edges[i][0], v = edges[i][1], w = edges[i][2];
if (graph[u].count >= graph[u].capacity) {
graph[u].capacity = graph[u].capacity == 0 ? 1 : graph[u].capacity * 2;
graph[u].edges = realloc(graph[u].edges, graph[u].capacity * sizeof(Edge));
}
graph[u].edges[graph[u].count++] = (Edge){v, w, i};
if (graph[v].count >= graph[v].capacity) {
graph[v].capacity = graph[v].capacity == 0 ? 1 : graph[v].capacity * 2;
graph[v].edges = realloc(graph[v].edges, graph[v].capacity * sizeof(Edge));
}
graph[v].edges[graph[v].count++] = (Edge){u, w, i};
}
pathCount = 0;
pathCapacity = 10;
allPaths = malloc(pathCapacity * sizeof(Path));
bool* visited = calloc(n, sizeof(bool));
int* usedEdges = malloc(edgesSize * sizeof(int));
visited[0] = true;
dfs(0, n-1, 0, usedEdges, 0, visited, graph, n);
if (pathCount > 0) {
int minCost = allPaths[0].cost;
for (int i = 1; i < pathCount; i++) {
if (allPaths[i].cost < minCost) {
minCost = allPaths[i].cost;
}
}
for (int i = 0; i < pathCount; i++) {
if (allPaths[i].cost == minCost) {
for (int j = 0; j < allPaths[i].edgeCount; j++) {
result[allPaths[i].edges[j]] = true;
}
}
}
}
// Cleanup
for (int i = 0; i < pathCount; i++) {
free(allPaths[i].edges);
}
free(allPaths);
free(visited);
free(usedEdges);
for (int i = 0; i < n; i++) {
free(graph[i].edges);
}
free(graph);
return result;
}
Time & Space Complexity
Time Complexity
β±οΈ
O(V! * E)
In worst case, we might explore V! different paths, and for each path we check all E edges
n
2n
β Linear Growth
Space Complexity
O(V * P)
We need to store all paths, where P is the number of paths and each path can have up to V vertices
n
2n
β Linear Space
52.3K Views
HighFrequency
~25 minAvg. Time
1.8K Likes
Ln 1, Col 1
Smart Actions
π‘Explanation
AI Ready
π‘ SuggestionTabto acceptEscto dismiss
// Output will appear here after running code
Code Editor Closed
Click the red button to reopen
Algorithm Visualization
Pinch to zoom β’ Tap outside to close
Test Cases
0 passed
0 failed
3 pending
Select Compiler
Choose a programming language
Compiler list would appear here...
AI Editor Features
Header Buttons
π‘
Explain
Get a detailed explanation of your code. Select specific code or analyze the entire file. Understand algorithms, logic flow, and complexity.
π§
Fix
Automatically detect and fix issues in your code. Finds bugs, syntax errors, and common mistakes. Shows you what was fixed.
π‘
Suggest
Get improvement suggestions for your code. Best practices, performance tips, and code quality recommendations.
π¬
Ask AI
Open an AI chat assistant to ask any coding questions. Have a conversation about your code, get help with debugging, or learn new concepts.
Smart Actions (Slash Commands)
π§
/fix Enter
Find and fix issues in your code. Detects common problems and applies automatic fixes.
π‘
/explain Enter
Get a detailed explanation of what your code does, including time/space complexity analysis.
π§ͺ
/tests Enter
Automatically generate unit tests for your code. Creates comprehensive test cases.
π
/docs Enter
Generate documentation for your code. Creates docstrings, JSDoc comments, and type hints.
β‘
/optimize Enter
Get performance optimization suggestions. Improve speed and reduce memory usage.
AI Code Completion (Copilot-style)
π»
Ghost Text Suggestions
As you type, AI suggests code completions shown in gray text. Works with keywords like def, for, if, etc.
Tabto acceptEscto dismiss
π¬
Comment-to-Code
Write a comment describing what you want, and AI generates the code. Try: # two sum, # binary search, # fibonacci
π‘
Pro Tip: Select specific code before using Explain, Fix, or Smart Actions to analyze only that portion. Otherwise, the entire file will be analyzed.