Algorithm

Network Delay Time

Graphs Pattern

Network Delay Time

You are given a network of n nodes labelled 1 to n and a list of travel times, each entry (u, v, w) meaning a signal takes w time to travel from node u to node v along a one-way link.

A signal is broadcast from node k and propagates along every outgoing link simultaneously. Return the time at which the last node receives it.

If any node can never receive the signal, return -1.

CONSTRAINTS
  • 1 <= k <= n <= 100
  • 1 <= times.length <= 6000
  • times[i] = (uᵢ, vᵢ, wᵢ) with 1 <= wᵢ <= 100
  • Links are directed — a link from u to v does not imply one from v to u
  • All weights are positive, so Dijkstra's greedy assumption holds
EXAMPLE 1
Input: times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
Output: 2
Nodes 1 and 3 each receive the signal at time 1, directly from node 2. Node 4 receives it at time 2, one unit after node 3. The answer is the latest of these arrivals, not their sum — the signal travels along all links at once.
EXAMPLE 2
Input: times = [[1,2,1]], n = 2, k = 2
Output: -1
The only link runs from node 1 to node 2, and the broadcast starts at node 2. Since links are one-way, node 1 can never be reached, so the answer is -1. Direction matters: a node with a link into the source is not thereby reachable from it.
EXAMPLE 3
Input: times = [], n = 1, k = 1
Output: 0
The single node is the source and receives the signal at time 0. With no other nodes to reach, no time elapses. An empty link list is not automatically -1.
EXAMPLE 4
Input: times = [[1,2,1],[1,3,4],[2,3,1]], n = 3, k = 1
Output: 2
Node 3 is reachable directly at time 4, but the route through node 2 delivers at 1 + 1 = 2, which is earlier. The signal arrives by whichever route is fastest, so node 3's arrival is 2 and the overall answer is 2 rather than 4.
Am I returning the sum of all delays or the time the last node receives the signal?
The time of the last arrival. The signal propagates along every link in parallel, so arrivals overlap — the answer is the maximum of the individual arrival times, never their total.
What if some node cannot be reached?
Return -1. Checking this means confirming every one of the n nodes has a finite arrival time, not just that the traversal visited something.
Are the nodes numbered from 0 or from 1?
From 1 to n. An array-based distance table therefore needs n+1 entries with index 0 unused, or a consistent offset. This off-by-one is the most common bug here.
Can travel times be zero or negative?
No, weights are at least 1. That guarantee is what makes the greedy shortest-path approach valid. If negative delays were somehow permitted, the algorithm would silently return wrong answers and Bellman-Ford would be needed.

The wording describes a signal spreading through a network, but the two questions hiding inside it are ordinary ones. First: when does each node receive the signal? Second: how do those individual answers combine into one?

What "when does the signal arrive" actually means

The signal leaves node k and travels along every outgoing link at once. When it reaches a node, that node immediately rebroadcasts along all of its own outgoing links.

So a node may be reached by several different routes, at several different times — and the arrival that matters is the earliest one, because once a node has the signal, later copies change nothing.

That phrasing is the entire translation. "Earliest arrival time at each node" is exactly "shortest path from the source to each node", with link delays as edge weights. Nodes are vertices, links are directed weighted edges, and the propagation is a single-source shortest-path computation.

Combining the arrivals

Now the second question, which is where people go wrong. Having computed every node's earliest arrival, what is the answer?

Not the sum. The signal is not carried from node to node in sequence by a single messenger — it spreads everywhere in parallel, so the delays overlap rather than accumulate. The network is fully informed at the moment the last node hears it, so the answer is the maximum over all arrival times.

And if any node's arrival is infinite, it is never reached at all, so the answer is -1. Note this must be checked against every node from 1 to n, including nodes that appear nowhere in the link list — an isolated node is unreachable and must produce -1.

The algorithm

Since every weight is positive, the greedy approach applies: repeatedly settle the unsettled node with the smallest known arrival time, and that time is final.

The justification is worth being able to give. Suppose u is the unsettled node with the smallest tentative arrival d, and imagine some faster route to u exists. That route begins at the settled source and ends at unsettled u, so it must pass through some first unsettled node x, whose tentative time is already at least d by the choice of u. The rest of the route from x to u has non-negative weight, so the total is at least d. No faster route exists. Non-negativity is precisely what makes that last step valid.

Keeping the smallest tentative time available needs a min-heap, whose top element is always the minimum and whose operations cost O(log n).

python
import heapq
from collections import defaultdict

def network_delay_time(times, n, k):
    adj = defaultdict(list)
    for u, v, w in times:
        adj[u].append((v, w))                 # directed: only one direction

    arrival = {}
    heap = [(0, k)]                           # (time, node)

    while heap:
        t, node = heapq.heappop(heap)
        if node in arrival:
            continue                          # already settled at an earlier time
        arrival[node] = t
        for nxt, w in adj[node]:
            if nxt not in arrival:
                heapq.heappush(heap, (t + w, nxt))

    if len(arrival) < n:
        return -1                             # some node never received it
    return max(arrival.values())
Crucial Notethe edge is added in one direction only. Appending the reverse as well would model two-way links and produce arrival times that are too small — a wrong answer with no error, since the code runs perfectly happily on the wrong graph.
Crucial Notethe check if node in arrival: continue is what makes each node settle exactly once. The heap accumulates several entries per node, one per route that reached it, and only the first popped — the smallest, by the heap's ordering — is correct. Without this guard a node would be reprocessed with inflated times.
Crucial Notethe reachability test compares against n, not against the number of distinct nodes appearing in the link list. A node mentioned nowhere still exists and still must be reached. Testing len(arrival) < len(adj) instead is a subtle bug that passes most examples.

Cost: each link pushes at most one heap entry, so O(E log V) time and O(V + E) space. With n at 100 and 6000 links this is negligible — Bellman-Ford's O(V × E), around 600,000 operations, would also pass comfortably and is easier to write correctly under pressure.

Worked example

times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2.

Adjacency: node 2 points to node 1 with weight 1 and to node 3 with weight 1; node 3 points to node 4 with weight 1. Nodes 1 and 4 have no outgoing links.

- Heap starts as [(0, 2)].
- Pop (0, 2). Not yet settled, so arrival[2] = 0. Push (1, 1) and (1, 3).
- Pop (1, 1). Settle arrival[1] = 1. Node 1 has no outgoing links.
- Pop (1, 3). Settle arrival[3] = 1. Push (2, 4).
- Pop (2, 4). Settle arrival[4] = 2. No outgoing links. Heap empties.

Four nodes settled out of four, so nothing is unreachable. Arrivals are 0, 1, 1 and 2, and the maximum is 2. Nodes 1 and 3 were informed simultaneously at time 1 — the delays ran in parallel, which is why the answer is 2 rather than 0 + 1 + 1 + 1.

Now times = [[1,2,1]], n = 2, k = 2. The adjacency list has node 1 pointing at node 2, and node 2 pointing nowhere. The heap starts as [(0, 2)], pops it, settles arrival[2] = 0, and finds no outgoing links. The heap empties with only one node settled out of two, so the answer is -1. Node 1 has a link to the source, which does nothing — directed edges only carry signal one way.

The takeaway

Two habits are worth taking from this.

The first is translation. Delay, latency, travel time, cost, distance are all the same thing to a shortest-path algorithm. The story changes; the graph does not. Once the mapping is stated — nodes are vertices, links are directed weighted edges, arrival time is shortest-path distance — the problem is a standard one.

The second is the aggregation step, which is where the actual thinking lives. Computing all the distances is routine; deciding what to do with the resulting table is what varies. Here the answer is the maximum, because parallel propagation finishes when the slowest branch finishes. A different question over identical distances — the average latency, the count of nodes within some threshold, the nearest server — needs a different reduction over the same table.

Train the reflex: when something spreads through a network and you are asked how long until everything is covered, compute each node's earliest arrival and take the maximum. The word "until everything" almost always means a maximum over shortest paths, never a sum.

Interactive Strategy Visualization

Dijkstra's Shortest Path

Greedy Relaxation
Optimal Distance
41238
A
D: 0
B
D: ∞
C
D: ∞
D
D: ∞
NodeShortest Distance
A0
B
C
D

1. The Initial State

We start at node A. We know the distance to A is 0, but all other nodes are 'infinitely' far away because we haven't explored them yet.

O(V × E) Bellman-Ford Repeated Relaxation
O(E log V) Dijkstra With Min-Heap
O(V) Final Maximum Scan