Skip to main content

Most Stones Removed with Same Row or Column

Problem Statement:

On a 2D plane, we place n stones at some integer coordinate points. Each coordinate point may have at most one stone.

A stone can be removed if it shares either the same row or the same column as another stone that has not been removed.

Given an array stones of length n where stones[i] = [xi, yi] represents the location of the ith stone, return the largest possible number of stones that can be removed.

  • Example:

    Example 1:

    Input: stones = [[0,0],[0,1],[1,0],[1,2],[2,1],[2,2]]
    Output: 5
    Explanation: One way to remove 5 stones is as follows:
    1. Remove stone [2,2] because it shares the same row as [2,1].
    2. Remove stone [2,1] because it shares the same column as [0,1].
    3. Remove stone [1,2] because it shares the same row as [1,0].
    4. Remove stone [1,0] because it shares the same column as [0,0].
    5. Remove stone [0,1] because it shares the same row as [0,0].
    Stone [0,0] cannot be removed since it does not share a row/column with another stone still on the plane.

    Example 2:

    Input: stones = [[0,0],[0,2],[1,1],[2,0],[2,2]]
    Output: 3
    Explanation: One way to make 3 moves is as follows:
    1. Remove stone [2,2] because it shares the same row as [2,0].
    2. Remove stone [2,0] because it shares the same column as [0,0].
    3. Remove stone [0,2] because it shares the same row as [0,0].
    Stones [0,0] and [1,1] cannot be removed since they do not share a row/column with another stone still on the plane.

    Example 3:

    Input: stones = [[0,0]]
    Output: 0
    Explanation: [0,0] is the only stone on the plane, so you cannot remove it.

✅ Solution: Disjoint Set (Union by Size) – Most Stones Removed with Same Row or Column


class DisjointSet {
public:
vector<int> parent, rank, size;

// Initialize parent, rank, and size arrays
DisjointSet(int n){
rank.resize(n + 1, 0);
parent.resize(n + 1);
size.resize(n + 1, 1);
for(int i = 0; i <= n; i++){
parent[i] = i; // Every node is initially its own parent
}
}

// Find the ultimate parent of a node with path compression
int findParent(int node){
if(parent[node] == node) return node;
return parent[node] = findParent(parent[node]);
}

// Union two nodes by size (attach smaller to larger)
void unionBySize(int u, int v){
int parentU = findParent(u);
int parentV = findParent(v);

if(parentU == parentV) return;

if(size[parentU] > size[parentV]){
parent[parentV] = parentU;
size[parentU] += size[parentV];
}
else {
parent[parentU] = parentV;
size[parentV] += size[parentU];
}
}
};

class Solution {
public:
int removeStones(vector<vector<int>>& stones) {
int maxRow = 0;
int maxCol = 0;
int totalStones = stones.size();

// Find the maximum row and column index used
for(int i = 0; i < stones.size(); i++){
maxRow = max(maxRow, stones[i][0]);
maxCol = max(maxCol, stones[i][1]);
}

// Create a DSU for (rows + cols). Offset cols to avoid collision.
DisjointSet ds(maxRow + maxCol + 1);

// Map to keep track of all unique nodes (row or col index used)
map<int, int> nodeUsed;

// Union each stone's row and (offset) column
for(auto it : stones){
int rowNode = it[0];
int colNode = it[1] + maxRow + 1; // offset col to make unique node id

ds.unionBySize(rowNode, colNode);

// Mark both nodes as used
nodeUsed[rowNode] = 1;
nodeUsed[colNode] = 1;
}

// Count number of connected components (unique parents)
int numComponents = 0;
for(auto it : nodeUsed){
int node = it.first;
if(ds.findParent(node) == node){
numComponents++;
}
}

// Max stones removable = total stones - number of components
return totalStones - numComponents;
}
};


📝 How It Works

  • You can remove a stone if there’s another stone in the same row or column.
  • Think of each stone as a connection between its row and column.
  • Use Disjoint Set Union to group all connected rows and columns.
  • Offset column index to avoid clash with row index (col + maxRow + 1).
  • After processing all unions:
    • Count how many unique connected components exist.
    • Answer is total stones - number of components.

🧩 Key Idea

  • Treat rows and columns as graph nodes.
  • Stones connect row ↔ column, forming a bipartite graph.
  • DSU groups stones into connected components.
  • Each connected component must leave at least one stone, others can be removed.

⏱️ Time & Space Complexity

MetricValue
⏱️ TimeO(N * α(N)) where α is inverse Ackermann
💾 SpaceO(R + C) where R is max row, C is max column

⚠️ Edge Cases

  • All stones in different rows/cols → no stone can be removed.
  • All stones in same row/column → all but one can be removed.

💡 Other Approaches

ApproachTimeNotes
DFS/BFSO(N²)Build row/col adjacency, less efficient
Union-Find ✅O(N * α(N))Most efficient

  • Leetcode 947: Most Stones Removed with Same Row or Column
  • Leetcode 1319: Make Network Connected
  • Leetcode 200: Number of Islands
  • Leetcode 990: Satisfiability of Equality Equations
💬

Discussion & Doubts