1584. Min Cost to Connect All Points - Explanation

Problem Link

Description

You are given a 2-D integer array points, where points[i] = [xi, yi]. Each points[i] represents a distinct point on a 2-D plane.

The cost of connecting two points [xi, yi] and [xj, yj] is the manhattan distance between the two points, i.e. |xi - xj| + |yi - yj|.

Return the minimum cost to connect all points together, such that there exists exactly one path between each pair of points.

Example 1:

Input: points = [[0,0],[2,2],[3,3],[2,4],[4,2]]

Output: 10

Constraints:

  • 1 <= points.length <= 1000
  • -1,000,000 <= xi, yi <= 1,000,000
  • All pairs (xi, yi) are distinct.


Topics

Recommended Time & Space Complexity

You should aim for a solution as good or better than O((n^2)logn) time and O(n^2) space, where n is the number of points.


Hint 1

Think of this problem as a graph, where the given points represent nodes. We need to connect these nodes into a single component by creating edges. Can you think of an advanced graph algorithm that can be used to connect all points into one component?


Hint 2

We use Kruskal's algorithm along with Union-Find (DSU) to connect nodes into components. The final component forms the minimum spanning tree (MST), where the edges between nodes are weighted by the Manhattan distance, and the total weight of the tree is minimized. How would you implement this?


Hint 3

We create the possible edges by iterating through every pair of points and calculating the weights as the Manhattan distance between them. Next, we sort the edges in ascending order based on their weights, as we aim to minimize the cost. Then, we traverse through these edges, connecting the nodes and adding the weight of the edge to the total cost if the edge is successfully added. The final result will be the minimum cost.


Company Tags

Please upgrade to NeetCode Pro to view company tags.



Prerequisites

Before attempting this problem, you should be comfortable with:

  • Graph Theory Basics - Understanding nodes, edges, and weighted graphs
  • Minimum Spanning Tree (MST) - The concept of connecting all nodes with minimum total edge weight
  • Union-Find (Disjoint Set Union) - Data structure for efficiently tracking connected components and detecting cycles
  • Priority Queue / Heap - For efficiently selecting the minimum weight edge in Prim's algorithm
  • Sorting - Sorting edges by weight for Kruskal's algorithm

1. Kruskal's Algorithm

Intuition

We want to connect all points such that the total cost is minimum, where the cost to connect two points is their Manhattan distance.
This is exactly the definition of a Minimum Spanning Tree (MST).

Kruskal's Algorithm fits naturally:

  • Treat each point as a node.
  • Treat the distance between every pair of points as an edge weight.
  • Always choose the cheapest edge that connects two different components.
  • Avoid cycles while connecting all nodes.

To efficiently check whether two points are already connected, we use Disjoint Set Union (Union-Find).

Algorithm

  1. Consider each point as a node.
  2. Generate all possible edges between pairs of points with their Manhattan distances.
  3. Sort all edges in increasing order of distance.
  4. Initialize a Disjoint Set Union (DSU) structure.
  5. Iterate through the sorted edges:
    • If the two points are in different sets:
      • Union them.
      • Add the edge cost to the total answer.
  6. Continue until all points are connected.
  7. Return the total cost.
class DSU:
    def __init__(self, n):
        self.Parent = list(range(n + 1))
        self.Size = [1] * (n + 1)

    def find(self, node):
        if self.Parent[node] != node:
            self.Parent[node] = self.find(self.Parent[node])
        return self.Parent[node]

    def union(self, u, v):
        pu = self.find(u)
        pv = self.find(v)
        if pu == pv:
            return False
        if self.Size[pu] < self.Size[pv]:
            pu, pv = pv, pu
        self.Size[pu] += self.Size[pv]
        self.Parent[pv] = pu
        return True

class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        dsu = DSU(n)
        edges = []
        for i in range(n):
            x1, y1 = points[i]
            for j in range(i + 1, n):
                x2, y2 = points[j]
                dist = abs(x1 - x2) + abs(y1 - y2)
                edges.append((dist, i, j))

        edges.sort()
        res = 0
        for dist, u, v in edges:
            if dsu.union(u, v):
                res += dist
        return res

Time & Space Complexity

  • Time complexity: O(n2logn)O(n ^ 2 \log n)
  • Space complexity: O(n2)O(n ^ 2)

2. Prim's Algorithm

Intuition

We still want a Minimum Spanning Tree (MST): connect all points with minimum total Manhattan distance.

Prim's Algorithm grows the MST one node at a time:

  • Start from any point (say point 0).
  • At every step, pick the cheapest edge that connects:
    • a point already in the MST
    • to a point not yet in the MST
  • Keep doing this until all points are included.

A min-heap (priority queue) is used to always get the next cheapest edge quickly.

Algorithm

  1. Build a graph where each pair of points has an edge with weight = Manhattan distance.
  2. Start MST from node 0.
  3. Push (0, 0) into a min-heap (cost to add starting node is 0).
  4. Maintain a visited set for nodes already in the MST.
  5. While visited size < N:
    • Pop the smallest (cost, node) from heap.
    • If node is already visited, skip it.
    • Otherwise:
      • Add cost to answer.
      • Mark node as visited.
      • Push all edges (edgeCost, neighbor) to heap for unvisited neighbors.
  6. The accumulated cost is the minimum cost to connect all points.
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        N = len(points)
        adj = {i: [] for i in range(N)}
        for i in range(N):
            x1, y1 = points[i]
            for j in range(i + 1, N):
                x2, y2 = points[j]
                dist = abs(x1 - x2) + abs(y1 - y2)
                adj[i].append([dist, j])
                adj[j].append([dist, i])

        res = 0
        visit = set()
        minH = [[0, 0]]
        while len(visit) < N:
            cost, i = heapq.heappop(minH)
            if i in visit:
                continue
            res += cost
            visit.add(i)
            for neiCost, nei in adj[i]:
                if nei not in visit:
                    heapq.heappush(minH, [neiCost, nei])
        return res

Time & Space Complexity

  • Time complexity: O(n2logn)O(n ^ 2 \log n)
  • Space complexity: O(n2)O(n ^ 2)

3. Prim's Algorithm (Optimal)

Intuition

We want to connect all points so that the total cost is minimum, where the cost to connect two points is their Manhattan distance.
This is exactly a Minimum Spanning Tree (MST) problem:

  • Think of each point as a node in a graph.
  • Every pair of points has an edge with weight = Manhattan distance.
  • We need the cheapest way to connect all nodes without forming unnecessary cycles → that’s an MST.

This solution uses Prim’s Algorithm (greedy MST building):

  • Start from any node (here, node 0).
  • Repeatedly add the closest unvisited node to the growing connected set.
  • Keep track of the best (minimum) known distance from the current MST to every unvisited node.

Instead of building all edges (which would be too many), we compute distances on the fly and update the best known connection cost for each node.


Algorithm

  1. Let n be the number of points.
  2. Create:
    • visit[i] → whether point i is already included in the MST
    • dist[i] → the minimum cost to connect point i to the current MST
      (initialize all as infinity)
  3. Start from node = 0 with total cost res = 0 and connected edges edges = 0.
  4. While we have added fewer than n - 1 edges:
    1. Mark the current node as visited (added to MST).
    2. For every unvisited point i:
      • Compute cost to connect i from the current node
      • Update dist[i] = min(dist[i], cost)
    3. Choose nextNode as the unvisited point with the smallest dist[i].
    4. Add dist[nextNode] to res (we are connecting nextNode to the MST).
    5. Move node = nextNode and increment edges.
  5. Return res as the total minimum cost.
class Solution:
    def minCostConnectPoints(self, points: List[List[int]]) -> int:
        n, node = len(points), 0
        dist = [100000000] * n
        visit = [False] * n
        edges, res = 0, 0

        while edges < n - 1:
            visit[node] = True
            nextNode = -1
            for i in range(n):
                if visit[i]:
                    continue
                curDist = (abs(points[i][0] - points[node][0]) +
                           abs(points[i][1] - points[node][1]))
                dist[i] = min(dist[i], curDist)
                if nextNode == -1 or dist[i] < dist[nextNode]:
                    nextNode = i

            res += dist[nextNode]
            node = nextNode
            edges += 1

        return res

Time & Space Complexity

  • Time complexity: O(n2)O(n ^ 2)
  • Space complexity: O(n)O(n)

Common Pitfalls

Using Euclidean Distance Instead of Manhattan Distance

The problem specifies Manhattan distance |x1 - x2| + |y1 - y2|, not Euclidean distance. Using the wrong distance formula will produce incorrect edge weights and ultimately a wrong MST cost.

Forgetting to Handle Self-Loops in Edge Generation

When generating all edges between points, ensure you only create edges between distinct points (i.e., i != j). Including self-loops with zero cost can corrupt the Union-Find structure or cause infinite loops in some implementations.

Not Stopping After N-1 Edges in MST Construction

A spanning tree with n nodes has exactly n-1 edges. Continuing to add edges after the MST is complete wastes time and, in some implementations, can cause issues. Always track the number of edges added and stop once you reach n-1.