Skip to content
ΣDSA Patterns
Menu
Language

Shortest Path (Weighted)

Guide 1 of 6 · Path 1 of 6

PreviousNext →

Interactive

Mental model

A worked animation for this problem. Scrub steps or press space to pause; re-tell the invariant out loud.

Step 1 of 7
S0A∞B∞T∞

dist[S]=0 · min-heap

Weighted shortest path. Edges: S→A 1, S→B 4, A→B 1, A→T 7, B→T 1. BFS hops are the wrong metric.

Demo preview: These solutions pass the automated test suite but have not been human-reviewed. Treat trade-offs and prose as draft.

Network Delay Time

Problem (restated)

A directed network of n nodes (1-indexed) and weighted edges times[i] = [u, v, w] (signal from u to v takes w). A signal starts at node k. Return the time for every node to receive it, or -1 if some node is unreachable.

Intuition

The time the last node hears the signal is the longest shortest-path from k. Weights are non-negative, so Dijkstra from k. Answer is max(dist[1..n]), or -1 if any dist is still infinite.

Approaches

Dijkstra from k

Unverified
Time O((n+E) log n)Space O(n+E)

Idea. Adjacency list of (v, w). dist[k] = 0, min-heap of (d, u). Pop the closest node; skip stale pops (d > dist[u]); relax dist[v] = d + w and push. Then take the max finite distance.

Walkthrough. n=4, k=2, edges 2→1 (1), 2→3 (1), 3→4 (1). Distances 1,0,1,2. Max 2.

Trade-offs. The template. Unreachable nodes stay ∞ → -1. BFS would be wrong: a cheap two-edge path can beat a costly one-edge path.

Solution
/**
 * Toy PQ: sort + shift. Interview/production: binary heap, O((V+E) log V).
 */
export function networkDelayTime(times: number[][], n: number, k: number): number {
  const adj: [number, number][][] = Array.from({ length: n + 1 }, () => []);
  for (const [u, v, w] of times) adj[u]!.push([v, w]);
  const dist = new Array<number>(n + 1).fill(Infinity);
  dist[k] = 0;
  const pq: [number, number][] = [[0, k]];
  while (pq.length) {
    pq.sort((a, b) => a[0]! - b[0]!);
    const [d, u] = pq.shift()!;
    if (d > dist[u]!) continue;
    for (const [v, w] of adj[u]!) {
      if (d + w < dist[v]!) {
        dist[v] = d + w;
        pq.push([dist[v]!, v]);
      }
    }
  }
  let ans = 0;
  for (let i = 1; i <= n; i++) {
    if (dist[i] === Infinity) return -1;
    ans = Math.max(ans, dist[i]!);
  }
  return ans;
}
/**
 * Toy PQ: sort + shift. Interview/production: binary heap, O((V+E) log V).
 */
export function networkDelayTime(times: number[][], n: number, k: number): number {
  const adj: [number, number][][] = Array.from({ length: n + 1 }, () => []);
  for (const [u, v, w] of times) adj[u]!.push([v, w]);
  const dist = new Array<number>(n + 1).fill(Infinity);
  dist[k] = 0;
  const pq: [number, number][] = [[0, k]];
  while (pq.length) {
    pq.sort((a, b) => a[0]! - b[0]!);
    const [d, u] = pq.shift()!;
    if (d > dist[u]!) continue;
    for (const [v, w] of adj[u]!) {
      if (d + w < dist[v]!) {
        dist[v] = d + w;
        pq.push([dist[v]!, v]);
      }
    }
  }
  let ans = 0;
  for (let i = 1; i <= n; i++) {
    if (dist[i] === Infinity) return -1;
    ans = Math.max(ans, dist[i]!);
  }
  return ans;
}

Template connection

Plain Dijkstra: min-heap by distance, relax on pop, skip stale entries. LC 1976 is the same loop plus path counts.

Reflection