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).

12 Core Algorithmic Patterns & 168 Practice Problems

  • 1. Two Pointers (9 Paradigms, 32 Problems): Converging pointers, sorted pair sums, container with most water, trapping rain water, 3Sum, plus the Sliding Window and Fast & Slow Pointers paradigms (Floyd cycle detection, monotonic window invariants, longest substrings, minimum window).
  • 2. Binary Search (8 Paradigms, 12 Problems): Monotonic predicate partitioning, boundary searching, rotated arrays, median of two sorted arrays, matrix median on value range.
  • 3. Bit Manipulation (5 Paradigms, 8 Problems): Bitmasking, XOR tricks, counting set bits, subset enumeration via bitmasks.
  • 4. Math & Geometry (5 Paradigms, 10 Problems): Sieve of Eratosthenes, integer/roman conversions, modular arithmetic, geometric simulation.
  • 5. Tree/Graph Depth-First Search (8 Paradigms, 17 Problems): Path sums, lowest common ancestor, tree diameter, subtree serialization, validating BSTs.
  • 6. Tree/Graph Breadth-First Search (4 Paradigms, 11 Problems): Level-order traversals, shortest path, rotting oranges, word ladders.
  • 7. Graphs (6 Paradigms, 14 Problems): Topological sort, cycle detection, Dijkstra, bipartite validation, network delay.
  • 8. Backtracking (5 Paradigms, 13 Problems): Subsets, permutations, combinations, constraint satisfaction, pruning, N-Queens.
  • 9. Dynamic Programming (7 Paradigms, 14 Problems): Memoization vs tabulation, knapsack, coin change, edit distance, longest common subsequence.
  • 10. Heap / Priority Queue (8 Paradigms, 10 Problems): Running medians, top-k elements, interval scheduling, IPO, k-way merges.
  • 11. Advanced Data Structures (5 Paradigms, 13 Problems): Trie, Union-Find, LRU Cache, LFU Cache, Monotonic Stacks.
  • 12. Intervals & Stack / Miscellaneous (7 Paradigms, 14 Problems): Merge intervals, daily temperatures, largest rectangle in histogram, trapping rain water via stack.

4-Stage Deliberate Practice Framework

  1. Stage 1 (Compare & Learn): Multi-language Rosetta Stone contrasting abstract invariants with concrete solutions across Python, C#, Java, TypeScript, C++, Go, and Rust.
  2. Stage 2 (Active Recall): Reconstruct algorithmic template invariants from memory with real-time feedback before looking at solutions.
  3. Stage 3 (Senior SWE AI Mock Coach): Simulated senior mock interview evaluating Big-O space/time tradeoffs, edge cases, and code reviews in Monaco Editor.
  4. Stage 4 (Solve on Your Own): Timed sandbox challenges verified against automated test suites in Python, C#, Java, and TypeScript.

Equipped with SM-2 Spaced Repetition Review Hub, Studio Cockpit workspace layout, and interactive study notes.

Pricing, Access & Commercial Terms

  • Core Curriculum: 100% Free. No credit card required.
  • Compute Coins: 40 free coins upon signup, +20 daily login bonus, +25 referral bonus.
  • 24-Hour AI Coaching Pass: 5 compute coins unlocks unlimited senior SWE AI coaching for a full 24 hours.
  • BYOK (Bring Your Own Key): Completely free unlimited AI coaching if using your own Gemini/OpenAI API key.
  • Refund & Subscription Policy: No recurring charges, no subscription traps, and no paid paywalls. Free tier provides full learning path.
  • Platform Operator: Hi👋WebEnterprise Inc. Support & policies at hispeedalgo.com.
Skip to main content
Hi👋SpeedAlgo

Invariant-First Algorithmic Mastery

180Items
Theory Context•Graph Algorithms
MediumLC 1135

Connecting Cities With Minimum Cost (LeetCode 1135)

You will see how sorting the links and joining groups with Union-Find finds the cheapest way to connect every city.

Target Frequency:AmazonGoogleUber

There are n cities, labeled 1 to n. Each connections[i] = [xi, yi, cost_i] says you can build a two-way link between city xi and city yi for cost_i.

Choose links so that every city can reach every other city through built links, and pay as little as possible in total. Return that smallest total, or -1 if even building every link leaves some cities cut off.

Worked Examples

Example 1
Input:n = 3, connections = [[1,2,5],[1,3,6],[2,3,1]]
Output:6
561123
Explanation: Any two links connect three cities, so take the two cheapest: `2-3` for 1 and `1-2` for 5.
Example 2
Input:n = 4, connections = [[1,2,3],[3,4,4]]
Output:-1
341234
Explanation: No link joins the pair `{1, 2}` to the pair `{3, 4}`, so the cities can't all be connected.

⚖️Formal Constraints & Bounds

  • 1 <= n <= 104

  • 1 <= connections.length <= 104

  • connections[i].length == 3

  • 1 <= xi, yi <= n

  • xi != yi

  • 0 <= cost_i <= 105

Deep-Dive & Conceptual Insights

Why It Works & Core Invariant

Take links from cheapest to most expensive and keep each one that joins two cities not yet connected (a Union-Find find tells); n - 1 kept links is a cheapest spanning tree, fewer means some city can't be reached.

Real-World Scenario & Production Applications

Laying cable, fibre or pipes between sites at the smallest total cost is a minimum spanning tree problem; so is clustering by stopping Kruskal early (single-linkage clustering). The same sort-and-union loop runs over any weighted edge list.

Step-by-Step Execution Trace Table

Input n = 3, connections = [[1,2,5],[1,3,6],[2,3,1]], sorted by cost: [2,3,1], [1,2,5], [1,3,6].

StepEdge [u, v, w]find(u), find(v)Same group?Actionmst_costedges_count
1[2, 3, 1]2, 3Notake it, parent[2] = 311
2[1, 2, 5]1, 3Notake it, parent[1] = 362 = n - 1, stop
Endedges_count == n - 1, return mst_cost6
Scroll horizontally to see all columns, or expand to full screen

Input n = 4, connections = [[1,2,3],[3,4,4]]: both edges are taken (edges_count = 2), the list ends with 2 < n - 1 = 3, so the answer is -1.

Trace Inputn = 3, connections = [[1,2,5],[1,3,6],[2,3,1]]
Expected6

Input n = 3, connections = [[1,2,5],[1,3,6],[2,3,1]], sorted by cost: [2,3,1], [1,2,5], [1,3,6].

StepEdge [u, v, w]find(u), find(v)Same group?Actionmst_costedges_count
1[2, 3, 1]2, 3Notake it, parent[2] = 311
2[1, 2, 5]1, 3Notake it, parent[1] = 362 = n - 1, stop
Endedges_count == n - 1, return mst_cost6
Scroll horizontally to see all columns, or expand to full screen

Input n = 4, connections = [[1,2,3],[3,4,4]]: both edges are taken (edges_count = 2), the list ends with 2 < n - 1 = 3, so the answer is -1.

Core Invariant Specification & Code Shape
Archetype Code Shape
Python
1The cheapest link between two separate groups is always safe to build; a link inside one group only closes a cycle.
2`find(u) != find(v)` says the ends are in different groups: take the edge, join the roots (`parent[root_u] = root_v`), add `w` to `mst_cost`, and count it in `edges_count`.
3`parent = list(range(n + 1))`, a `find` with path halving, sort `connections` by cost, loop and take safe edges, stop at `n - 1` edges.
4The trap: return `mst_cost` only if `edges_count == n - 1`; fewer edges means the cities are not all connected, so return `-1`.

Target: Connecting Cities With Minimum Cost (LeetCode 1135). Cities are labeled 1..n, so the list has n + 1 slots and index 0 is unused.

Boundary Model: Graph Component Traversal & Visited State Machine

Maintains visited set or 3-color states (WHITE=unvisited, GREY=visiting/cycle, BLACK=processed) across adjacency lists.

Loop Invariant Termination

Loop outer vertices 0..V-1 to handle disconnected subgraphs; explore edges via BFS/DFS/PriorityQueue.

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

To join every city at the lowest total cost you need a minimum spanning tree: n - 1 links, no cycles, smallest total weight. Kruskal's algorithm builds it greedily: look at the links from cheapest to most expensive, and take a link only when its two cities are still in different groups. A Union-Find (parent plus find) answers "same group?" almost instantly, and joining two groups is one assignment.

🏟️ The Analogy: Building Bridges Between Islands

Picture every city as its own island. You have a price list of possible bridges. Go down the list from the cheapest: if a bridge links two islands that are not yet reachable from each other, build it and treat the two as one bigger island. If they are already reachable, the bridge would only make a loop, so skip it. When everything is one island you are done; if the list runs out first, some islands can never be reached.

🪄 The Mathematical Harmony / Magic Trick
Code / Blueprint
connections.sort(key=lambda e: e[2])
for u, v, w in connections:
root_u, root_v = find(u), find(v)
if root_u != root_v: # different groups: safe to take
parent[root_u] = root_v
mst_cost += w
edges_count += 1
return mst_cost if edges_count == n - 1 else -1
 

Why the cheapest crossing edge is safe: any full wiring must cross the gap between two separate groups somewhere; if it used a more expensive crossing, swapping in the cheaper one keeps everything connected and never costs more. An edge whose ends share a root would only close a cycle, so skipping it loses nothing.

💡 Summary

Sort the edges, take each one that joins two different Union-Find groups, and stop at n - 1 edges. Fewer than n - 1 edges after the whole list means the cities can't all be joined: return -1. Sorting dominates: O(Elog⁡E)O(E \log E)O(ElogE) time, O(V)O(V)O(V) extra space for parent.

  • Returning the partial cost when the graph is disconnected: after the loop, edges_count < n - 1 means some cities were never reached. Return -1, not mst_cost: on n = 4, [[1,2,3],[3,4,4]] the partial cost is 7 but the answer is -1.

  • Joining the nodes instead of the roots: parent[u] = v can cut u off from its own group and leave two roots for one group. Always join parent[root_u] = root_v.

  • No path compression: without the parent[x] = parent[parent[x]] step, chains grow and each find can walk O(n) links, making the whole run O(E * V).

  • Off-by-one on labels: cities are labeled 1..n, so parent needs n + 1 slots; list(range(n)) crashes on city n.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

You will see how a senior engineer recognizes a minimum spanning tree and defends Kruskal's greedy choice.

Pattern Recognition Signals

The 10-second spot

"Connect all the cities" with the "minimum total cost" over a list of weighted links: every city must be reachable, but the cost is paid per link, not per route. That is a minimum spanning tree, and with the links given as an edge list, Kruskal's MST (sort plus Union-Find) is the direct fit.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

The edges taken so far form a forest that is part of some minimum spanning tree, and find gives one root to exactly the cities they connect; an edge is taken exactly when find(u) != find(v).

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • return mst_cost if edges_count == n - 1 else -1: fewer than n - 1 edges means the graph is disconnected, so return -1 instead of the partial cost.

  • parent[root_u] = root_v: join the roots, not the original nodes, or a group can end up with two roots.

  • parent[x] = parent[parent[x]]: without path compression, find walks long chains and the run slows to O(E * V).

  • parent = list(range(n + 1)): cities are labeled 1..n.

The 60-Second Interview Pitch

Say this out loud before you type a single line

This is a minimum spanning tree, so I'd use Kruskal's MST. I sort the connections by cost and keep a Union-Find over the cities. For each connection, cheapest first, I find both cities' roots. If the roots differ, the link joins two separate groups, so I take it: I join the roots, add its cost, and count it. If the roots match, it would only close a cycle, so I skip it. Taking the cheapest link across any gap is safe, because any full wiring must cross that gap somewhere and swapping in the cheaper link never costs more. I stop once I have n minus one links. The trap is the end: if I finish the list with fewer than n minus one links, some cities are unreachable and I return minus one, not the partial cost. Sorting dominates, so it's O(E log E) time, with O(V) space for the parent array.

So: sort by cost, find(u) != find(v) then union and add, stop at n - 1 edges, else -1.

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(E log E)

Look at the code: connections.sort(key=lambda e: e[2]) costs O(E log E). The loop visits each of the E edges at most once; each iteration calls find twice, and with path halving a find costs amortized O(log V) at worst (nearly constant in practice), which is below the sort's per-edge O(log E). Total: O(E log E).

SPACE COMPLEXITY

O(V)

parent holds n + 1 entries: O(V). The edges are sorted in place in the input list; the counters are O(1). (Python's sort may use a temporary buffer while it runs.)

Formal Recurrence Relation

T(V, E) = O(E log E) + E · O(find) = O(E log E)

Look at the code: connections.sort(key=lambda e: e[2]) costs O(E log E). The loop visits each of the E edges at most once; each iteration calls find twice, and with path halving a find costs amortized O(log V) at worst (nearly constant in practice), which is below the sort's per-edge O(log E). Total: O(E log E).

Derivation Progression

Build Union-Find

O(V)

parent = list(range(n + 1)).

Sort edges

O(E log E)

connections.sort(key=lambda e: e[2]).

Scan edges

E × 2 finds

Each edge is looked at once; find with path halving is nearly constant, at most O(log V) amortized.

Total

O(E log E)

The sort dominates the scan.

Variable Definitions

VVV

Number of cities, n

EEE

Number of candidate links, len(connections)

Memory Architecture & Bounds

🟣 Call Stack

O(1): find is iterative

🔵 Auxiliary Heap

O(V): the parent array

🟢 Output Space

O(1): one integer

Boundary Best / Worst Cases

Best Case

O(Elog⁡E)O(E \log E)O(ElogE): the sort runs even if the first n - 1 edges already connect everything

Average Case

O(Elog⁡E)O(E \log E)O(ElogE)

Worst Case

O(Elog⁡E)O(E \log E)O(ElogE)

Graph & Tree Traversal Frontier

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

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

Triggers: "every city can reach every other city", "pay as little as possible in total", "list of [x, y, cost] links". Connect all nodes at minimum total edge weight: a minimum spanning tree, built with Kruskal's MST over the edge list.

CONSTRAINTS & BOUNDS

n≤104n \le 10^4n≤104 cities, E≤104E \le 10^4E≤104 links, costs up to 10510^5105: the total is at most 104⋅105=10910^4 \cdot 10^5 = 10^9104⋅105=109, which fits a 32-bit signed integer. Budget: O(Elog⁡E)O(E \log E)O(ElogE) time, O(V)O(V)O(V) space.

FAANG PRODUCTION TRAPS & EDGE CASES

A disconnected input must return -1, not the partial cost. At scale, Kruskal needs the whole edge list sorted up front; when edges arrive as a stream or don't fit in memory, sort externally or use Prim's algorithm on an adjacency structure instead.

Core Algorithmic State Invariants

1. Safe Forest

The edges taken so far always form a forest that is part of some minimum spanning tree: each new edge is the cheapest remaining one between two separate groups.

2. One Root per Group

`find` gives one root to exactly the cities the taken edges connect. `find(u) == find(v)` means the edge would close a cycle, so it is skipped; otherwise `parent[root_u] = root_v` merges the groups.

3. n - 1 or -1

A spanning tree on n cities has exactly n - 1 edges. Reaching `edges_count == n - 1` returns `mst_cost`; finishing with fewer returns -1. Sorting gives O(E log E) time, `parent` O(V) space.

Theory Context•Graph Algorithms
MediumLC 1135

Connecting Cities With Minimum Cost (LeetCode 1135)

You will see how sorting the links and joining groups with Union-Find finds the cheapest way to connect every city.

Target Frequency:AmazonGoogleUber

There are n cities, labeled 1 to n. Each connections[i] = [xi, yi, cost_i] says you can build a two-way link between city xi and city yi for cost_i.

Choose links so that every city can reach every other city through built links, and pay as little as possible in total. Return that smallest total, or -1 if even building every link leaves some cities cut off.

Worked Examples

Example 1
Input:n = 3, connections = [[1,2,5],[1,3,6],[2,3,1]]
Output:6
561123
Explanation: Any two links connect three cities, so take the two cheapest: `2-3` for 1 and `1-2` for 5.
Example 2
Input:n = 4, connections = [[1,2,3],[3,4,4]]
Output:-1
341234
Explanation: No link joins the pair `{1, 2}` to the pair `{3, 4}`, so the cities can't all be connected.

⚖️Formal Constraints & Bounds

  • 1 <= n <= 104

  • 1 <= connections.length <= 104

  • connections[i].length == 3

  • 1 <= xi, yi <= n

  • xi != yi

  • 0 <= cost_i <= 105

Deep-Dive & Conceptual Insights

Why It Works & Core Invariant

Take links from cheapest to most expensive and keep each one that joins two cities not yet connected (a Union-Find find tells); n - 1 kept links is a cheapest spanning tree, fewer means some city can't be reached.

Real-World Scenario & Production Applications

Laying cable, fibre or pipes between sites at the smallest total cost is a minimum spanning tree problem; so is clustering by stopping Kruskal early (single-linkage clustering). The same sort-and-union loop runs over any weighted edge list.

Step-by-Step Execution Trace Table

Input n = 3, connections = [[1,2,5],[1,3,6],[2,3,1]], sorted by cost: [2,3,1], [1,2,5], [1,3,6].

StepEdge [u, v, w]find(u), find(v)Same group?Actionmst_costedges_count
1[2, 3, 1]2, 3Notake it, parent[2] = 311
2[1, 2, 5]1, 3Notake it, parent[1] = 362 = n - 1, stop
Endedges_count == n - 1, return mst_cost6
Scroll horizontally to see all columns, or expand to full screen

Input n = 4, connections = [[1,2,3],[3,4,4]]: both edges are taken (edges_count = 2), the list ends with 2 < n - 1 = 3, so the answer is -1.

Trace Inputn = 3, connections = [[1,2,5],[1,3,6],[2,3,1]]
Expected6

Input n = 3, connections = [[1,2,5],[1,3,6],[2,3,1]], sorted by cost: [2,3,1], [1,2,5], [1,3,6].

StepEdge [u, v, w]find(u), find(v)Same group?Actionmst_costedges_count
1[2, 3, 1]2, 3Notake it, parent[2] = 311
2[1, 2, 5]1, 3Notake it, parent[1] = 362 = n - 1, stop
Endedges_count == n - 1, return mst_cost6
Scroll horizontally to see all columns, or expand to full screen

Input n = 4, connections = [[1,2,3],[3,4,4]]: both edges are taken (edges_count = 2), the list ends with 2 < n - 1 = 3, so the answer is -1.

Core Invariant Specification & Code Shape
Archetype Code Shape
Python
1The cheapest link between two separate groups is always safe to build; a link inside one group only closes a cycle.
2`find(u) != find(v)` says the ends are in different groups: take the edge, join the roots (`parent[root_u] = root_v`), add `w` to `mst_cost`, and count it in `edges_count`.
3`parent = list(range(n + 1))`, a `find` with path halving, sort `connections` by cost, loop and take safe edges, stop at `n - 1` edges.
4The trap: return `mst_cost` only if `edges_count == n - 1`; fewer edges means the cities are not all connected, so return `-1`.

Target: Connecting Cities With Minimum Cost (LeetCode 1135). Cities are labeled 1..n, so the list has n + 1 slots and index 0 is unused.

Boundary Model: Graph Component Traversal & Visited State Machine

Maintains visited set or 3-color states (WHITE=unvisited, GREY=visiting/cycle, BLACK=processed) across adjacency lists.

Loop Invariant Termination

Loop outer vertices 0..V-1 to handle disconnected subgraphs; explore edges via BFS/DFS/PriorityQueue.

Conceptual Narrative

🧭 Conceptual Foundation & Pattern Intuition

To join every city at the lowest total cost you need a minimum spanning tree: n - 1 links, no cycles, smallest total weight. Kruskal's algorithm builds it greedily: look at the links from cheapest to most expensive, and take a link only when its two cities are still in different groups. A Union-Find (parent plus find) answers "same group?" almost instantly, and joining two groups is one assignment.

🏟️ The Analogy: Building Bridges Between Islands

Picture every city as its own island. You have a price list of possible bridges. Go down the list from the cheapest: if a bridge links two islands that are not yet reachable from each other, build it and treat the two as one bigger island. If they are already reachable, the bridge would only make a loop, so skip it. When everything is one island you are done; if the list runs out first, some islands can never be reached.

🪄 The Mathematical Harmony / Magic Trick
Code / Blueprint
connections.sort(key=lambda e: e[2])
for u, v, w in connections:
root_u, root_v = find(u), find(v)
if root_u != root_v: # different groups: safe to take
parent[root_u] = root_v
mst_cost += w
edges_count += 1
return mst_cost if edges_count == n - 1 else -1
 

Why the cheapest crossing edge is safe: any full wiring must cross the gap between two separate groups somewhere; if it used a more expensive crossing, swapping in the cheaper one keeps everything connected and never costs more. An edge whose ends share a root would only close a cycle, so skipping it loses nothing.

💡 Summary

Sort the edges, take each one that joins two different Union-Find groups, and stop at n - 1 edges. Fewer than n - 1 edges after the whole list means the cities can't all be joined: return -1. Sorting dominates: O(Elog⁡E)O(E \log E)O(ElogE) time, O(V)O(V)O(V) extra space for parent.

  • Returning the partial cost when the graph is disconnected: after the loop, edges_count < n - 1 means some cities were never reached. Return -1, not mst_cost: on n = 4, [[1,2,3],[3,4,4]] the partial cost is 7 but the answer is -1.

  • Joining the nodes instead of the roots: parent[u] = v can cut u off from its own group and leave two roots for one group. Always join parent[root_u] = root_v.

  • No path compression: without the parent[x] = parent[parent[x]] step, chains grow and each find can walk O(n) links, making the whole run O(E * V).

  • Off-by-one on labels: cities are labeled 1..n, so parent needs n + 1 slots; list(range(n)) crashes on city n.

Senior SWE Reasoning Architecture

4-Phase Thought Process Model

You will see how a senior engineer recognizes a minimum spanning tree and defends Kruskal's greedy choice.

Pattern Recognition Signals

The 10-second spot

"Connect all the cities" with the "minimum total cost" over a list of weighted links: every city must be reachable, but the cost is paid per link, not per route. That is a minimum spanning tree, and with the links given as an edge list, Kruskal's MST (sort plus Union-Find) is the direct fit.

Formulating the Predicate & Invariants

Turning intuition into a boolean rule

The edges taken so far form a forest that is part of some minimum spanning tree, and find gives one root to exactly the cities they connect; an edge is taken exactly when find(u) != find(v).

Silent Failure Traps & Edge Cases

Where confident candidates still lose points

  • return mst_cost if edges_count == n - 1 else -1: fewer than n - 1 edges means the graph is disconnected, so return -1 instead of the partial cost.

  • parent[root_u] = root_v: join the roots, not the original nodes, or a group can end up with two roots.

  • parent[x] = parent[parent[x]]: without path compression, find walks long chains and the run slows to O(E * V).

  • parent = list(range(n + 1)): cities are labeled 1..n.

The 60-Second Interview Pitch

Say this out loud before you type a single line

This is a minimum spanning tree, so I'd use Kruskal's MST. I sort the connections by cost and keep a Union-Find over the cities. For each connection, cheapest first, I find both cities' roots. If the roots differ, the link joins two separate groups, so I take it: I join the roots, add its cost, and count it. If the roots match, it would only close a cycle, so I skip it. Taking the cheapest link across any gap is safe, because any full wiring must cross that gap somewhere and swapping in the cheaper link never costs more. I stop once I have n minus one links. The trap is the end: if I finish the list with fewer than n minus one links, some cities are unreachable and I return minus one, not the partial cost. Sorting dominates, so it's O(E log E) time, with O(V) space for the parent array.

So: sort by cost, find(u) != find(v) then union and add, stop at n - 1 edges, else -1.

Big-O Invariant Derivation

Complexity & Mathematical Proof

TIME COMPLEXITY

O(E log E)

Look at the code: connections.sort(key=lambda e: e[2]) costs O(E log E). The loop visits each of the E edges at most once; each iteration calls find twice, and with path halving a find costs amortized O(log V) at worst (nearly constant in practice), which is below the sort's per-edge O(log E). Total: O(E log E).

SPACE COMPLEXITY

O(V)

parent holds n + 1 entries: O(V). The edges are sorted in place in the input list; the counters are O(1). (Python's sort may use a temporary buffer while it runs.)

Formal Recurrence Relation

T(V, E) = O(E log E) + E · O(find) = O(E log E)

Look at the code: connections.sort(key=lambda e: e[2]) costs O(E log E). The loop visits each of the E edges at most once; each iteration calls find twice, and with path halving a find costs amortized O(log V) at worst (nearly constant in practice), which is below the sort's per-edge O(log E). Total: O(E log E).

Derivation Progression

Build Union-Find

O(V)

parent = list(range(n + 1)).

Sort edges

O(E log E)

connections.sort(key=lambda e: e[2]).

Scan edges

E × 2 finds

Each edge is looked at once; find with path halving is nearly constant, at most O(log V) amortized.

Total

O(E log E)

The sort dominates the scan.

Variable Definitions

VVV

Number of cities, n

EEE

Number of candidate links, len(connections)

Memory Architecture & Bounds

🟣 Call Stack

O(1): find is iterative

🔵 Auxiliary Heap

O(V): the parent array

🟢 Output Space

O(1): one integer

Boundary Best / Worst Cases

Best Case

O(Elog⁡E)O(E \log E)O(ElogE): the sort runs even if the first n - 1 edges already connect everything

Average Case

O(Elog⁡E)O(E \log E)O(ElogE)

Worst Case

O(Elog⁡E)O(E \log E)O(ElogE)

Graph & Tree Traversal Frontier

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

Senior SWE Deconstruction & Hardware Caveats

ARCHITECTURAL SIGNALS & INTERVIEW TRIGGERS

Triggers: "every city can reach every other city", "pay as little as possible in total", "list of [x, y, cost] links". Connect all nodes at minimum total edge weight: a minimum spanning tree, built with Kruskal's MST over the edge list.

CONSTRAINTS & BOUNDS

n≤104n \le 10^4n≤104 cities, E≤104E \le 10^4E≤104 links, costs up to 10510^5105: the total is at most 104⋅105=10910^4 \cdot 10^5 = 10^9104⋅105=109, which fits a 32-bit signed integer. Budget: O(Elog⁡E)O(E \log E)O(ElogE) time, O(V)O(V)O(V) space.

FAANG PRODUCTION TRAPS & EDGE CASES

A disconnected input must return -1, not the partial cost. At scale, Kruskal needs the whole edge list sorted up front; when edges arrive as a stream or don't fit in memory, sort externally or use Prim's algorithm on an adjacency structure instead.

Core Algorithmic State Invariants

1. Safe Forest

The edges taken so far always form a forest that is part of some minimum spanning tree: each new edge is the cheapest remaining one between two separate groups.

2. One Root per Group

`find` gives one root to exactly the cities the taken edges connect. `find(u) == find(v)` means the edge would close a cycle, so it is skipped; otherwise `parent[root_u] = root_v` merges the groups.

3. n - 1 or -1

A spanning tree on n cities has exactly n - 1 edges. Reaching `edges_count == n - 1` returns `mst_cost`; finishing with fewer returns -1. Sorting gives O(E log E) time, `parent` O(V) space.

Rosetta Dual-Monaco Comparison
Python 3
CANONICAL INVARIANT TEMPLATE
Loading...
CONCRETE: CONNECTING CITIES WITH MINIMUM COST (LEETCODE 1135)
T = O(E log E)S = O(V)
Loading...
Pattern Implementation Mapping TableCanonical Invariant ⟷ Concrete Code ⟷ Engineering Rationale
Canonical InvariantConcrete CodeEngineering Rationale
Every node starts as its own groupparent = list(range(n + 1))Cities are labeled 1..n, so the list has n + 1 slots and index 0 is unused.
find returns a group's root, shortening the path as it goeswhile parent[x] != x: parent[x] = parent[parent[x]] x = parent[x]Path halving keeps the trees shallow, so each find is almost O(1).
Cheapest edges firstconnections.sort(key=lambda e: e[2])Kruskal's greedy choice: the cheapest edge between two groups is always safe.
Take an edge only if it joins two different groupsif root_u != root_v: parent[root_u] = root_vEqual roots mean the edge would close a cycle; different roots are joined at their roots.
Count the edges taken and stop at n - 1edges_count += 1 if edges_count == n - 1: breakA spanning tree on n nodes has exactly n - 1 edges; nothing later can help.
Connected only if n - 1 edges were takenreturn mst_cost if edges_count == n - 1 else -1Fewer edges after the whole list means at least two groups never met.
© 2026 Hi👋WebEnterprise. All rights reserved.
Sitemap•llms.txt•