Hi👋SpeedAlgo • Deliberate Practice & Cognitive Ergonomics for Software Engineers

An interactive algorithm mastery and technical interview preparation platform published by Hi👋WebEnterprise. Built for senior and staff software engineers preparing for rigorous coding screens at top tech companies (FAANG/MAMAA).

13 Core Algorithmic Patterns & 225 Practice Problems

  • 1. Two Pointers (16 Paradigms, 43 Problems): Opposite ends, sorted pair sums, palindrome verification, trapping rain water, 3Sum, container with most water — includes the Sliding Window and Fast & Slow Pointers paradigms (contiguous subarray invariants, longest substrings, Floyd's cycle detection, linked list middle).
  • 2. Binary Search (9 Paradigms, 14 Problems): Monotonic predicate partitioning (feasible(x)), boundary search, rotated sorted arrays, square roots, minimum ship capacity, median of two sorted arrays, matrix median on value range.
  • 3. Bit Manipulation (5 Paradigms, 11 Problems): Counting set bits, XOR cancellation, bit reversal, bitmask pairing, maximum XOR with a bitwise trie.
  • 4. Math & Geometry (8 Paradigms, 14 Problems): Sieve of Eratosthenes, integer/roman conversions, modular arithmetic, geometric simulation.
  • 5. Tree/Graph Depth-First Search (15 Paradigms, 24 Problems): Path sums, lowest common ancestor, tree diameter, validating BSTs, tree DP (House Robber III, Binary Tree Cameras).
  • 6. Tree/Graph Breadth-First Search (5 Paradigms, 12 Problems): Level-order traversals, shortest path in unweighted graphs, zig-zag traversals, rotting oranges, word ladders.
  • 7. Graphs (12 Paradigms, 22 Problems): Topological sort, cycle detection, Dijkstra's algorithm, bipartite graph validation, network delay.
  • 8. Backtracking (6 Paradigms, 14 Problems): Subsets, permutations, combinations, constraint satisfaction, pruning, N-Queens, Sudoku solver.
  • 9. Dynamic Programming (13 Paradigms, 28 Problems): Memoization vs tabulation, 0/1 knapsack, unbounded knapsack, coin change, edit distance, longest common subsequence.
  • 10. Heap / Priority Queue (9 Paradigms, 11 Problems): Running medians, top-k elements, interval scheduling, IPO, k-way merges.
  • 11. Advanced Data Structures (7 Paradigms, 17 Problems): Trie (prefix tree), Union-Find (Disjoint Set Union), LRU Cache, LFU Cache, range-sum queries with updates.
  • 12. Stack (5 Paradigms, 9 Problems): Next greater element, largest rectangle in histogram, remove k digits, decode string, min stack.
  • 13. Intervals & Greedy (2 Paradigms, 6 Problems): Merge intervals, interval scheduling, meeting rooms by sweep line, jump game.

4-Stage Deliberate Practice Framework

  1. Stage 1 (Compare & Learn): Read the pattern's mental model, loop invariant and Big-O proof, compare the pattern's template with the problem's solution side by side, and use the step-by-step debugger. The solution can also be shown in C#, Java, TypeScript, C++, Go or Rust for almost every problem.
  2. Stage 2 (Active Recall): Rebuild the solution from memory in a code editor, with an invariant checklist and optional progressive hints, and check it against a judged test suite.
  3. Stage 3 (AI Interview Coach, coming soon): A mock-interview stage still in development; for now, students go straight from Stage 2 to Stage 4.
  4. Stage 4 (Solve on Your Own): Solve a new problem on your own against a 15-minute timer; your code is graded against a test suite. Python and TypeScript run in your browser and C# runs on our server (design problems grade in Python and TypeScript).

Equipped with a spaced-repetition review hub on a fixed 7-step schedule (1 day up to 90 days), a two-pane Studio workspace, and study notes.

Pricing, Access & Commercial Terms

  • Core Curriculum: 100% Free. No credit card required.
  • Coins: New accounts get 40 free coins once, the daily claim adds +20 coins once a day, and inviting a friend earns you +25 coins when they complete their first practice step. These are the only ways to earn coins.
  • AI Coach: Each AI coach question costs 1-5 coins, priced by the server according to its size.
  • BYOK (Bring Your Own Key): AI coaching is free with your own Google Gemini, OpenAI or OpenRouter API key (BYOK).
  • Extras: Coins also unlock extras for 24 hours: a Recall hint level (1 coin), a Solve solution reveal (2), a LeetCode problem card's solutions (1) and a pattern's extra canonical problems (1).
  • Payments & Refunds: Nothing on the site is sold for money: coins can only be earned, never bought. There are no subscriptions or charges, so there is nothing to refund.
  • Platform Operator: Hi👋WebEnterprise. Support & policies at hispeedalgo.com.
Skip to main content
Hi👋SpeedAlgo

Invariant-First Algorithmic Mastery

Arena
238Items
Theory Context•Graph Algorithms
MediumLC 743

Network Delay Time (LeetCode 743)

Target Frequency:AmazonMicrosoftGoogle

A network has n nodes, labeled 1 through n, connected by directed wires times[i] = (ui, vi, wi): a signal takes wi time units to travel from ui to vi.

A signal is broadcast from a single node k. Return the time it takes for the last node to receive it -- the smallest t such that every one of the n nodes has heard the signal by time t. Return -1 if some node never receives it.

Worked Examples

Example 1
Input:times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
Output:2
1112134
Explanation: From node 2 the signal reaches nodes 1 and 3 at time 1, then node 4 at time 2.
Example 2
Input:times = [[1,2,1]], n = 2, k = 1
Output:1
Explanation: Node 2 hears the signal at time 1.
Example 3
Input:times = [[1,2,1]], n = 2, k = 2
Output:-1
Explanation: The only wire runs from 1 to 2, so a signal starting at 2 never reaches 1.

⚖️Formal Constraints & Bounds

  • 1 <= k <= n <= 100

  • 1 <= times.length <= 6000

  • times[i].length == 3

  • 1 <= ui, vi <= n

  • ui != vi

  • 0 <= wi <= 100

  • All the pairs (ui, vi) are unique. (i.e., no multiple edges.)

Deep-Dive & Conceptual Insights

Core Insight

Dijkstra finalizes node distances in monotonically increasing order. With non-negative edge weights, the first time a node is popped from the min-heap represents its globally optimal shortest path.

Real-World Scenario & Production Applications

GPS navigation routing (Google Maps/OSRM finding lowest-latency traffic routes) and packet routing in telecommunication networks (OSPF).

Subproblems & Recurrence Decomposition3 Phases

🧩Subproblem 1: Min-Heap Distance Initialization

Initialize distance map dist = {k: 0} and min-heap [(0, k)]. All other vertices start with infinite distance.

Mathematical Recurrence / Code Invariant
min_heap = [(0, k)]  # (distance, node)
dist = {k: 0}

Step-by-Step Execution Trace Table

StepPopped Element (dist, node)ActionFinalized dist TableHeap State After Relaxation
0—Seed source node k = 1{}[(0, 1)]
1(0, 1)Finalize node 1 at dist 0. Relax neighbors 2 (w=1) and 3 (w=7).{1: 0}[(1, 2), (7, 3)]
2(1, 2)Finalize node 2 at dist 1. Relax neighbor 3 (w=2 →\to→ dist 3).{1: 0, 2: 1}[(3, 3), (7, 3)]
3(3, 3)Finalize node 3 at dist 3. Relax neighbor 4 (w=1 →\to→ dist 4).{1: 0, 2: 1, 3: 3}[(4, 4), (7, 3)]
4(4, 4)Finalize node 4 at dist 4.{1: 0, 2: 1, 3: 3, 4: 4}[(7, 3)]
5(7, 3)Node 3 already in dist →\to→ stale entry pruned!{1: 0, 2: 1, 3: 3, 4: 4}[]
Trace Inputtimes = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
Expected2
StepPopped Element (dist, node)ActionFinalized dist TableHeap State After Relaxation
0—Seed source node k = 1{}[(0, 1)]
1(0, 1)Finalize node 1 at dist 0. Relax neighbors 2 (w=1) and 3 (w=7).{1: 0}[(1, 2), (7, 3)]
2(1, 2)Finalize node 2 at dist 1. Relax neighbor 3 (w=2 →\to→ dist 3).{1: 0, 2: 1}[(3, 3), (7, 3)]
3(3, 3)Finalize node 3 at dist 3. Relax neighbor 4 (w=1 →\to→ dist 4).{1: 0, 2: 1, 3: 3}[(4, 4), (7, 3)]
4(4, 4)Finalize node 4 at dist 4.{1: 0, 2: 1, 3: 3, 4: 4}[(7, 3)]
5(7, 3)Node 3 already in dist →\to→ stale entry pruned!{1: 0, 2: 1, 3: 3, 4: 4}[]
Code Shape
Archetype Code Shape
Python
1adj = [[] for _ in range(n + 1)]
2adj[u].append((v, w)) for every edge
3dist = {every node: inf}; dist[k] = 0
4pq = [(0, k)]
5while pq:
6 d, u = heappop(pq)
7 if d > dist[u]:
8 continue
9 for v, weight in adj[u]:
10 if dist[u] + weight < dist[v]:
11 dist[v] = dist[u] + weight
12 heappush(pq, (dist[v], v))
13answer = max(dist.values())
14return answer if answer < inf else -1

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

Dijkstra's algorithm finds the shortest path from a single source to all other nodes in a directed graph with non-negative edge weights. A priority queue greedily extracts the unvisited vertex with the smallest provisional distance. Relaxing outgoing edges guarantees that when a node is popped from the min-heap, its minimal distance is finalized. The overall delay time is the maximum of the shortest distances to all reachable nodes.

🚦 The Analogy: A Toll Road Network Where You Always Take the Cheapest Ticket Next

Imagine you're tracking the cheapest known cost to reach every city from your starting point, and you keep a stack of "tickets" for cities you haven't finalized yet, sorted cheapest-first. You always process the cheapest ticket on top of the stack next. Once you finalize a city's cost, you never need to revisit it — because every other route to it would have to pass through a city that's at least as expensive as the one you just finalized (since no road costs a negative toll), which can only make the total more expensive, never less.

🔑 The Key Idea in the Code

The if d > dist[u]: continue guard handles the case where a node got pushed onto the heap multiple times at different candidate distances — only the pop whose cost still equals dist[u] is trusted; every later, more expensive entry for that same node is simply discarded.

  • Missing Dijkstra stale heap entry skip: In lazy Dijkstra, nodes pushed with earlier, worse distances remain in the heap. Without if d > dist[u]: continue, every stale copy of u scans adj[u] again: the answer stays right, but the edge scans are no longer E in total, and dense graphs slow down badly.

  • 1-based node indexing off-by-one: Vertices are labeled from 1 to n. Allocating dist array of size n instead of n + 1 causes IndexError: list index out of range.

  • Unreachable node output error: Returning max(dist.values()) without checking if any node was never reached. If len(dist) < n (or any dist[i] == float('inf')), the signal cannot reach all nodes; you must return -1.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

The wires are directed, "a signal takes wi time units to travel from ui to vi" with 0 <= wi, and the answer is the moment "every one of the n nodes has heard the signal": each node hears it along its cheapest path from k, and the answer is the largest of those times. Cheapest paths from one source with non-negative weights is Dijkstra.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

Whenever (d, u) is popped with d == dist[u], dist[u] is final: no path to u is shorter. A popped entry with d > dist[u] is stale and skipped; otherwise each edge u -> v is relaxed with dist[u] + weight < dist[v], and only an improved dist[v] is pushed.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

This problem's traps are in Common Pitfalls above.

The 60-Second Interview Pitch

Say this out loud before you type a single line

"Every node hears the signal along its cheapest path from k, and the weights are never negative, so I'd use Dijkstra. I keep dist, the best known time per node, and a min-heap of time and node pairs, starting with zero at k. I always pop the smallest time. With non-negative weights, any other way to reach that node has to leave the settled area through a node that is at least as far, so the popped time is final. Then I relax each outgoing edge, and push a neighbour only when its time improves. The trap is the stale entry: a node can be in the heap several times, so when the popped time is bigger than dist of u, I skip it; otherwise old copies rescan their edges. The answer is the largest dist, or minus one if some node is still unreached. It's O((V plus E) log V) time and O(V plus E) space."

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O((V + E) log V)

Look at the code: building adj reads the E edges once and dist gets V entries, O(V + E). A pop that is not stale has d == dist[u], and with non-negative weights dist[u] never drops after that, so each node scans adj[u] at most once: E edge checks in total. Each check pushes at most once (only when dist[v] improves), so pq sees at most E + 1 pushes and E + 1 pops. A heap operation on at most E + 1 entries costs O(log E), and log E <= 2 log V because E <= V^2. Total: O(V + E) setup plus O(E log V) heap work, written O((V + E) log V).

SPACE COMPLEXITY

O(V + E)

adj holds V + 1 lists with E entries, dist holds V entries, and pq holds at most E + 1 entries at once, since each push comes from one edge check. There is no recursion. The answer is one integer.

Formal Recurrence Relation

T(V, E) = (V + E) setup + E edge checks + (E + 1) pushes and pops * O(log V) = O((V + E) log V)

Derivation Progression

Build adj and dist

adj = [[] for _ in range(n + 1)], dist over 1..n: O(V); for u, v, w in times: O(E)

Every edge is stored once in its source's list.

Each node scans its edges once

if d > dist[u]: continue skips every pop but the one with d == dist[u]: E edge checks in total

With non-negative weights dist[u] is final once popped, so adj[u] is scanned once.

Heap work

at most E + 1 heappush and E + 1 heappop, O(log E) = O(log V) each

A push happens only when dist[v] improves, at most once per edge check; log E <= 2 log V.

The answer

max(dist.values()): O(V)

The largest settled time, or -1 if some node is still infinite.

Variable Definitions

VVV

Number of nodes, n

EEE

Number of directed edges, len(times)

Memory Architecture & Bounds

🟣 Call Stack

O(1): no recursion

🔵 Auxiliary Heap

O(V + E): adj (E entries), dist (V entries) and pq (at most E + 1 entries)

🟢 Output Space

O(1): one integer

Boundary Best / Worst Cases

Best Case

O(V+E)O(V + E)O(V+E) when the source has no outgoing edge: dist and adj are still built, and pq pops once.

Average Case

O((V+E)log⁡V)O((V + E) \log V)O((V+E)logV).

Worst Case

O((V+E)log⁡V)O((V + E) \log V)O((V+E)logV) when many edges improve a dist and push, so pq grows toward E entries.

Graph & Tree Traversal Frontier

Graph & Tree Traversal Frontier
Synthesizing vector architecture diagram...
Staff+ Engineering Perspective

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

Scale signal: Bellman-Ford's V⋅EV \cdot EV⋅E relaxations are fine here (100⋅6000=6×105100 \cdot 6000 = 6 \times 10^5100⋅6000=6×105), but road and computer networks with millions of nodes need Dijkstra's O((V+E)log⁡V)O((V + E) \log V)O((V+E)logV).

CONSTRAINTS & BOUNDS

n≤100n \le 100n≤100 nodes, at most 6000 edges, weights 0..1000..1000..100: every edge is checked once, so pq never holds more than E+1E + 1E+1 entries.

FAANG PRODUCTION TRAPS & EDGE CASES

A negative weight (a refund, a credit) silently breaks the settled-means-final rule, so check the input at the boundary. When only one target matters, as in route planning, stop as soon as the target is popped instead of settling every node.

Core Algorithmic State Invariants

  1. Example 1, Settled in Order

From k = 2: node 2 pops at time 0, nodes 1 and 3 at time 1, node 4 at time 2. Every node is reached, so the answer is the largest time, 2.

Theory Context•Graph Algorithms
MediumLC 743

Network Delay Time (LeetCode 743)

Target Frequency:AmazonMicrosoftGoogle

A network has n nodes, labeled 1 through n, connected by directed wires times[i] = (ui, vi, wi): a signal takes wi time units to travel from ui to vi.

A signal is broadcast from a single node k. Return the time it takes for the last node to receive it -- the smallest t such that every one of the n nodes has heard the signal by time t. Return -1 if some node never receives it.

Worked Examples

Example 1
Input:times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
Output:2
1112134
Explanation: From node 2 the signal reaches nodes 1 and 3 at time 1, then node 4 at time 2.
Example 2
Input:times = [[1,2,1]], n = 2, k = 1
Output:1
Explanation: Node 2 hears the signal at time 1.
Example 3
Input:times = [[1,2,1]], n = 2, k = 2
Output:-1
Explanation: The only wire runs from 1 to 2, so a signal starting at 2 never reaches 1.

⚖️Formal Constraints & Bounds

  • 1 <= k <= n <= 100

  • 1 <= times.length <= 6000

  • times[i].length == 3

  • 1 <= ui, vi <= n

  • ui != vi

  • 0 <= wi <= 100

  • All the pairs (ui, vi) are unique. (i.e., no multiple edges.)

Deep-Dive & Conceptual Insights

Core Insight

Dijkstra finalizes node distances in monotonically increasing order. With non-negative edge weights, the first time a node is popped from the min-heap represents its globally optimal shortest path.

Real-World Scenario & Production Applications

GPS navigation routing (Google Maps/OSRM finding lowest-latency traffic routes) and packet routing in telecommunication networks (OSPF).

Subproblems & Recurrence Decomposition3 Phases

🧩Subproblem 1: Min-Heap Distance Initialization

Initialize distance map dist = {k: 0} and min-heap [(0, k)]. All other vertices start with infinite distance.

Mathematical Recurrence / Code Invariant
min_heap = [(0, k)]  # (distance, node)
dist = {k: 0}

Step-by-Step Execution Trace Table

StepPopped Element (dist, node)ActionFinalized dist TableHeap State After Relaxation
0—Seed source node k = 1{}[(0, 1)]
1(0, 1)Finalize node 1 at dist 0. Relax neighbors 2 (w=1) and 3 (w=7).{1: 0}[(1, 2), (7, 3)]
2(1, 2)Finalize node 2 at dist 1. Relax neighbor 3 (w=2 →\to→ dist 3).{1: 0, 2: 1}[(3, 3), (7, 3)]
3(3, 3)Finalize node 3 at dist 3. Relax neighbor 4 (w=1 →\to→ dist 4).{1: 0, 2: 1, 3: 3}[(4, 4), (7, 3)]
4(4, 4)Finalize node 4 at dist 4.{1: 0, 2: 1, 3: 3, 4: 4}[(7, 3)]
5(7, 3)Node 3 already in dist →\to→ stale entry pruned!{1: 0, 2: 1, 3: 3, 4: 4}[]
Trace Inputtimes = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
Expected2
StepPopped Element (dist, node)ActionFinalized dist TableHeap State After Relaxation
0—Seed source node k = 1{}[(0, 1)]
1(0, 1)Finalize node 1 at dist 0. Relax neighbors 2 (w=1) and 3 (w=7).{1: 0}[(1, 2), (7, 3)]
2(1, 2)Finalize node 2 at dist 1. Relax neighbor 3 (w=2 →\to→ dist 3).{1: 0, 2: 1}[(3, 3), (7, 3)]
3(3, 3)Finalize node 3 at dist 3. Relax neighbor 4 (w=1 →\to→ dist 4).{1: 0, 2: 1, 3: 3}[(4, 4), (7, 3)]
4(4, 4)Finalize node 4 at dist 4.{1: 0, 2: 1, 3: 3, 4: 4}[(7, 3)]
5(7, 3)Node 3 already in dist →\to→ stale entry pruned!{1: 0, 2: 1, 3: 3, 4: 4}[]
Code Shape
Archetype Code Shape
Python
1adj = [[] for _ in range(n + 1)]
2adj[u].append((v, w)) for every edge
3dist = {every node: inf}; dist[k] = 0
4pq = [(0, k)]
5while pq:
6 d, u = heappop(pq)
7 if d > dist[u]:
8 continue
9 for v, weight in adj[u]:
10 if dist[u] + weight < dist[v]:
11 dist[v] = dist[u] + weight
12 heappush(pq, (dist[v], v))
13answer = max(dist.values())
14return answer if answer < inf else -1

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

Dijkstra's algorithm finds the shortest path from a single source to all other nodes in a directed graph with non-negative edge weights. A priority queue greedily extracts the unvisited vertex with the smallest provisional distance. Relaxing outgoing edges guarantees that when a node is popped from the min-heap, its minimal distance is finalized. The overall delay time is the maximum of the shortest distances to all reachable nodes.

🚦 The Analogy: A Toll Road Network Where You Always Take the Cheapest Ticket Next

Imagine you're tracking the cheapest known cost to reach every city from your starting point, and you keep a stack of "tickets" for cities you haven't finalized yet, sorted cheapest-first. You always process the cheapest ticket on top of the stack next. Once you finalize a city's cost, you never need to revisit it — because every other route to it would have to pass through a city that's at least as expensive as the one you just finalized (since no road costs a negative toll), which can only make the total more expensive, never less.

🔑 The Key Idea in the Code

The if d > dist[u]: continue guard handles the case where a node got pushed onto the heap multiple times at different candidate distances — only the pop whose cost still equals dist[u] is trusted; every later, more expensive entry for that same node is simply discarded.

  • Missing Dijkstra stale heap entry skip: In lazy Dijkstra, nodes pushed with earlier, worse distances remain in the heap. Without if d > dist[u]: continue, every stale copy of u scans adj[u] again: the answer stays right, but the edge scans are no longer E in total, and dense graphs slow down badly.

  • 1-based node indexing off-by-one: Vertices are labeled from 1 to n. Allocating dist array of size n instead of n + 1 causes IndexError: list index out of range.

  • Unreachable node output error: Returning max(dist.values()) without checking if any node was never reached. If len(dist) < n (or any dist[i] == float('inf')), the signal cannot reach all nodes; you must return -1.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

Pattern Recognition Signals

The 10-second spot

The wires are directed, "a signal takes wi time units to travel from ui to vi" with 0 <= wi, and the answer is the moment "every one of the n nodes has heard the signal": each node hears it along its cheapest path from k, and the answer is the largest of those times. Cheapest paths from one source with non-negative weights is Dijkstra.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

Whenever (d, u) is popped with d == dist[u], dist[u] is final: no path to u is shorter. A popped entry with d > dist[u] is stale and skipped; otherwise each edge u -> v is relaxed with dist[u] + weight < dist[v], and only an improved dist[v] is pushed.

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

This problem's traps are in Common Pitfalls above.

The 60-Second Interview Pitch

Say this out loud before you type a single line

"Every node hears the signal along its cheapest path from k, and the weights are never negative, so I'd use Dijkstra. I keep dist, the best known time per node, and a min-heap of time and node pairs, starting with zero at k. I always pop the smallest time. With non-negative weights, any other way to reach that node has to leave the settled area through a node that is at least as far, so the popped time is final. Then I relax each outgoing edge, and push a neighbour only when its time improves. The trap is the stale entry: a node can be in the heap several times, so when the popped time is bigger than dist of u, I skip it; otherwise old copies rescan their edges. The answer is the largest dist, or minus one if some node is still unreached. It's O((V plus E) log V) time and O(V plus E) space."

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O((V + E) log V)

Look at the code: building adj reads the E edges once and dist gets V entries, O(V + E). A pop that is not stale has d == dist[u], and with non-negative weights dist[u] never drops after that, so each node scans adj[u] at most once: E edge checks in total. Each check pushes at most once (only when dist[v] improves), so pq sees at most E + 1 pushes and E + 1 pops. A heap operation on at most E + 1 entries costs O(log E), and log E <= 2 log V because E <= V^2. Total: O(V + E) setup plus O(E log V) heap work, written O((V + E) log V).

SPACE COMPLEXITY

O(V + E)

adj holds V + 1 lists with E entries, dist holds V entries, and pq holds at most E + 1 entries at once, since each push comes from one edge check. There is no recursion. The answer is one integer.

Formal Recurrence Relation

T(V, E) = (V + E) setup + E edge checks + (E + 1) pushes and pops * O(log V) = O((V + E) log V)

Derivation Progression

Build adj and dist

adj = [[] for _ in range(n + 1)], dist over 1..n: O(V); for u, v, w in times: O(E)

Every edge is stored once in its source's list.

Each node scans its edges once

if d > dist[u]: continue skips every pop but the one with d == dist[u]: E edge checks in total

With non-negative weights dist[u] is final once popped, so adj[u] is scanned once.

Heap work

at most E + 1 heappush and E + 1 heappop, O(log E) = O(log V) each

A push happens only when dist[v] improves, at most once per edge check; log E <= 2 log V.

The answer

max(dist.values()): O(V)

The largest settled time, or -1 if some node is still infinite.

Variable Definitions

VVV

Number of nodes, n

EEE

Number of directed edges, len(times)

Memory Architecture & Bounds

🟣 Call Stack

O(1): no recursion

🔵 Auxiliary Heap

O(V + E): adj (E entries), dist (V entries) and pq (at most E + 1 entries)

🟢 Output Space

O(1): one integer

Boundary Best / Worst Cases

Best Case

O(V+E)O(V + E)O(V+E) when the source has no outgoing edge: dist and adj are still built, and pq pops once.

Average Case

O((V+E)log⁡V)O((V + E) \log V)O((V+E)logV).

Worst Case

O((V+E)log⁡V)O((V + E) \log V)O((V+E)logV) when many edges improve a dist and push, so pq grows toward E entries.

Graph & Tree Traversal Frontier

Graph & Tree Traversal Frontier
Synthesizing vector architecture diagram...
Staff+ Engineering Perspective

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

Scale signal: Bellman-Ford's V⋅EV \cdot EV⋅E relaxations are fine here (100⋅6000=6×105100 \cdot 6000 = 6 \times 10^5100⋅6000=6×105), but road and computer networks with millions of nodes need Dijkstra's O((V+E)log⁡V)O((V + E) \log V)O((V+E)logV).

CONSTRAINTS & BOUNDS

n≤100n \le 100n≤100 nodes, at most 6000 edges, weights 0..1000..1000..100: every edge is checked once, so pq never holds more than E+1E + 1E+1 entries.

FAANG PRODUCTION TRAPS & EDGE CASES

A negative weight (a refund, a credit) silently breaks the settled-means-final rule, so check the input at the boundary. When only one target matters, as in route planning, stop as soon as the target is popped instead of settling every node.

Core Algorithmic State Invariants

  1. Example 1, Settled in Order

From k = 2: node 2 pops at time 0, nodes 1 and 3 at time 1, node 4 at time 2. Every node is reached, so the answer is the largest time, 2.

© 2026 Hi👋WebEnterprise. All rights reserved.
Sitemap•llms.txt•