Min Cost to Connect All Points
Problem
Given an array points where points[i] = [xi, yi] represents a point on the 2D plane, return the minimum cost to make all points connected such that there is exactly one simple path between any two points. The cost of connecting two points is the Manhattan distance between them.
- 1 ≤ points.length ≤ 1000
- −10⁶ ≤ xi, yi ≤ 10⁶
- All points are distinct
Example
points = [[0,0],[2,2],[3,10],[5,2],[7,0]]20The algorithm constructs a minimum spanning tree (MST) connecting all points with minimum total cost. It starts from point 0 with cost 0, adds edges to neighbors with their Manhattan distances, and uses a min-heap to greedily select the next edge with the smallest cost that connects a new point. The MST edges chosen are (0-1), (1-3), (3-4), and (1-2) with costs 4, 3, 5, and 8 respectively, summing to 20.
Approach
Straightforward Solution
A brute-force approach would consider all edges between points (O(N^2)) and run a standard MST algorithm like Kruskal's or Prim's. However, explicitly storing all edges is expensive and unnecessary.
Core Observation
The problem reduces to finding a minimum spanning tree (MST) over a complete graph where vertices are points and edge weights are Manhattan distances. The MST ensures all points are connected with minimum total edge cost.
Path to Optimal
Prim's algorithm can be adapted to this problem by dynamically computing edges from the current MST to unvisited points, using a min-heap to select the next minimal edge. This avoids storing all edges upfront and achieves O(N^2 log N) time by pushing edges lazily. The key insight is that Manhattan distances can be computed on the fly, and the min-heap efficiently picks the next best edge.
Optimal Approach
Build an adjacency list representing the complete graph with Manhattan distances. Use a min-heap initialized with the starting point (cost 0). Repeatedly pop the smallest edge from the heap, skip if the point is visited, otherwise add its cost to the result and push all edges from this point to unvisited neighbors into the heap. Continue until all points are visited. This yields the MST cost efficiently.
Time
O(N^2 log N)
Constructing the adjacency list requires O(N^2) to compute all pairwise Manhattan distances. The main loop runs until all N points are visited, and each edge insertion into the heap costs O(log N). Since each point can push up to O(N) edges, the total complexity is O(N^2 log N).
Space
O(N^2)
The adjacency list stores all edges between points, which is O(N^2). The min-heap can hold up to O(N^2) edges in the worst case. This space is necessary for this approach since the graph is complete.
Pattern Spotlight
Heap / Priority Queue (Prim's Algorithm for MST)
Use a min-heap to greedily select the next minimum cost edge connecting the growing MST to unvisited nodes, dynamically generating edges to avoid storing the entire graph explicitly.
Solution
| 1 | import heapq
|
| 2 |
|
| 3 | class Solution:
|
| 4 | def minCostConnectPoints(self, points: list[list[int]]) -> int:
|
| 5 | N = len(points)
|
| 6 | adj = { i:[] for i in range(N) }
|
| 7 | for i in range(N):
|
| 8 | x1, y1 = points[i]
|
| 9 | for j in range(i + 1, N):
|
| 10 | x2, y2 = points[j]
|
| 11 | dist = abs(x1 - x2) + abs(y1 - y2)
|
| 12 | adj[i].append([dist, j])
|
| 13 | adj[j].append([dist, i])
|
| 14 |
|
| 15 | res = 0
|
| 16 | visit = set()
|
| 17 | min_heap = [[0, 0]]
|
| 18 | while len(visit) < N:
|
| 19 | cost, i = heapq.heappop(min_heap)
|
| 20 | if i in visit:
|
| 21 | continue
|
| 22 | res += cost
|
| 23 | visit.add(i)
|
| 24 | for nei_cost, nei in adj[i]:
|
| 25 | if nei not in visit:
|
| 26 | heapq.heappush(min_heap, [nei_cost, nei])
|
| 27 | return res |
Step-by-Step Solution
Construct Complete Graph with Manhattan Distances
| 5 | N = len(points)
|
| 6 | adj = { i:[] for i in range(N) }
|
| 7 | for i in range(N):
|
| 8 | x1, y1 = points[i]
|
| 9 | for j in range(i + 1, N):
|
| 10 | x2, y2 = points[j]
|
| 11 | dist = abs(x1 - x2) + abs(y1 - y2)
|
| 12 | adj[i].append([dist, j])
|
| 13 | adj[j].append([dist, i])
|
Objective
To build an adjacency list representing all edges between points with their Manhattan distances as weights.
Key Insight
The problem models a complete graph where each point connects to every other with an edge weighted by Manhattan distance. Precomputing these distances and storing them in an adjacency list allows efficient access during MST construction. Although this requires O(N^2) time and space, it enables quick edge lookups during the main algorithm.
Interview Quick-Check
Core Logic
Compute Manhattan distance for every pair of points and store bidirectional edges in the adjacency list to represent the complete graph.
Complexity
This step takes O(N^2) time and space, which is acceptable given the problem constraints.
Common Pitfalls & Bugs
Forgetting to add edges in both directions (i to j and j to i) would break the undirected graph assumption.
Apply Prim's Algorithm Using a Min-Heap to Build MST
| 15 | res = 0
|
| 16 | visit = set()
|
| 17 | min_heap = [[0, 0]]
|
| 18 | while len(visit) < N:
|
| 19 | cost, i = heapq.heappop(min_heap)
|
| 20 | if i in visit:
|
| 21 | continue
|
| 22 | res += cost
|
| 23 | visit.add(i)
|
| 24 | for nei_cost, nei in adj[i]:
|
| 25 | if nei not in visit:
|
| 26 | heapq.heappush(min_heap, [nei_cost, nei])
|
| 27 | return res |
Objective
To iteratively select the minimum cost edge connecting the MST to an unvisited point, accumulating the total cost.
Key Insight
Prim's algorithm grows the MST by starting from an arbitrary node and repeatedly adding the smallest edge that connects a new point. Using a min-heap to store candidate edges ensures efficient retrieval of the next minimal edge. The visited set prevents cycles by skipping already included points. This approach guarantees the MST with minimal total cost.
Interview Quick-Check
Core Logic
Use a min-heap to always pick the smallest edge connecting the MST to an unvisited point, adding its cost and expanding the MST.
State & Boundaries
Continue until all points are visited, ensuring the MST spans all nodes.
Common Pitfalls & Bugs
Skipping edges leading to already visited points is critical to avoid cycles and incorrect cost accumulation.
Complexity
Heap operations dominate runtime, but the approach remains efficient for up to 1000 points.
Line Analysis
This solution has 3 Critical lines interviewers watch for.
min_heap = [[0, 0]]
Initialize min-heap with starting point 0 and cost 0.
Starting the MST from point 0 with zero cost seeds the algorithm and ensures the heap always has candidate edges.
cost, i = heapq.heappop(min_heap)
Pop the smallest cost edge from the heap.
Selecting the minimal edge ensures the MST grows optimally by always adding the least costly connection.
return res
Return the total cost of the MST after all points are connected.
The accumulated cost represents the minimum cost to connect all points with no cycles, fulfilling the problem requirement.
dist = abs(x1 - x2) + abs(y1 - y2)
Calculate Manhattan distance between points i and j.
Manhattan distance defines the edge weight, which is the cost to connect these two points.
visit = set()
Create a set to track visited points.
Visited set prevents cycles and ensures each point is added to the MST exactly once.
if i in visit:
Skip if the point is already visited.
Avoids cycles and redundant processing by ignoring edges leading to points already in the MST.
res += cost
Add the edge cost to the total MST cost.
Accumulates the cost of the newly added edge, progressively building the MST's total cost.
visit.add(i)
Mark the current point as visited.
Records that this point is now part of the MST, preventing future cycles and redundant edges.
if nei not in visit:
Check if neighbor point is unvisited.
Only unvisited neighbors are candidates for MST expansion, ensuring no cycles are formed.
heapq.heappush(min_heap, [nei_cost, nei])
Push neighbor edge into the min-heap for future consideration.
Adds candidate edges to the heap, maintaining the priority queue of minimal edges for MST growth.
adj = { i:[] for i in range(N) }
Initialize adjacency list as a dictionary with empty lists for each point.
This data structure will hold all edges for each point, enabling efficient access to neighbors and their edge costs.
adj[i].append([dist, j])
Add edge from i to j with computed distance.
Storing this edge in adjacency list allows quick access to neighbors during MST construction.
adj[j].append([dist, i])
Add edge from j to i with computed distance to maintain undirected graph.
Ensures the graph is undirected by storing edges in both directions, which is essential for correct MST traversal.
while len(visit) < N:
Loop until all points are visited.
Ensures the MST spans all points by continuing until every point is included.
continue
Continue to next iteration if point was visited.
This control flow prevents adding duplicate edges and maintains correctness of MST construction.
for nei_cost, nei in adj[i]:
Iterate over neighbors of the current point.
Explores all edges from the newly added point to unvisited points, expanding the MST frontier.
for i in range(N):
Iterate over each point index i to build edges.
Outer loop to pair each point with all subsequent points, ensuring all edges are considered once.
for j in range(i + 1, N):
Iterate over each point index j greater than i to avoid duplicate edges.
Inner loop pairs point i with all points after it, ensuring each edge is processed once and stored bidirectionally.
res = 0
Initialize result variable to accumulate total MST cost.
This variable will sum the costs of all edges included in the MST.
N = len(points)
Store the number of points in variable N.
Caching the number of points avoids repeated calls to len(points) and clarifies the problem size for subsequent loops.
x1, y1 = points[i]
Extract x and y coordinates of point i.
Coordinates are needed to compute Manhattan distances to other points.
x2, y2 = points[j]
Extract x and y coordinates of point j.
Coordinates of the second point in the pair are required for distance calculation.
Test Your Understanding
Why does Prim's algorithm guarantee the minimum total cost to connect all points?
Prim's algorithm grows the MST by always choosing the smallest edge connecting the current tree to an unvisited node, ensuring no cycles and minimal incremental cost at each step, which leads to a globally minimum spanning tree.
Related Problems
Heaps pattern
Don't just read it. Drill it.
Reconstruct Min Cost to Connect All Points from memory until it sticks. AlgoDrill blanks out key lines and makes you fill them back in, step by step.
Unlock the Min Cost to Connect All Points drill