dfs
union find
graph
]
Leetcode 0947. Most Stones Removed with Same Row or Column
Problem statement
https://leetcode.com/problems/most-stones-removed-with-same-row-or-column/
Solution 1
First solution is using idea of union find: we connect two stones if they have equal coordinate x or equal coordinate y. What is problem actually asking is number of connected components. We create graph with nodes: columns and rows (x1, ..., xn, y1, ..., yn), where we say two nodes are connected if we have stone in the intersection of column and row (that is graph is bipartitie). We can decode comumns by shift by N, with big enough value. Then when we run
for i, j in stones: dsu.union(i, j + N)
in this line we add N edges to our graph. Finally we just check number of components.
Complexity
It is O(n) if we use DSU with ranks and path compressions.
Code
class DSU:
def __init__(self, graph):
self.p = {i:i for i in graph}
def find(self, x):
if self.p[x] != x:
self.p[x] = self.find(self.p[x])
return self.p[x]
def union(self, x, y):
self.p[self.find(x)] = self.find(y)
class Solution:
def removeStones(self, stones):
N = 10000
graph = [i for i, j in stones] + [j + N for i, j in stones]
dsu = DSU(graph)
for i, j in stones: dsu.union(i, j + N)
groups = set(dsu.find(el) for el in graph)
return len(stones) - len(groups)
Solution 2
We can solve this with dfs as well. We have two types of nodes: for every column create all possible connections for this column , same for row. In fact, no need to create all connections, we can only add connection between adjacent nodes in each column (and row). Like (1, 1) - (3, 1) - (5, 1) - (10, 1) for the second one and full 4-element graph for the first one. Not neccecarily sort each row\column, in this way we will have truly linear complexity: if we connect (1, 1) -> (10, 1) -> (3, 1) -> (5, 1) then components are still the same.
Complexity
Time and space complexity is O(n).
Code
class Solution:
def removeStones(self, stones):
def dfs(q):
visited.add(q)
for neib in graph[q]:
if neib not in visited: dfs(neib)
rows, cols = defaultdict(list), defaultdict(list)
graph, visited, ans = defaultdict(list), set(), 0
for i, j in stones:
rows[i].append(j)
cols[j].append(i)
for r, k in rows.items():
for i, j in zip(k, k[1:]):
graph[r, i].append((r, j))
graph[r, j].append((r, i))
for c, k in cols.items():
for i, j in zip(k, k[1:]):
graph[i, c].append((j, c))
graph[j, c].append((i, c))
for i, j in stones:
if (i, j) not in visited:
dfs((i, j))
ans += 1
return len(stones) - ans