# 947. Most Stones Removed with Same Row or Column

**<font color=red>难度: Medium</font>**

## 刷题内容

> 原题连接

* https://leetcode.com/problems/most-stones-removed-with-same-row-or-column/

> 内容描述

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

Now, a move consists of removing a stone that shares a column or row with another stone on the grid.

What is the largest possible number of moves we can make?

 

Example 1:

Input: stones = [[0,0],[0,1],[1,0],[1,2],[2,1],[2,2]]
Output: 5
Example 2:

Input: stones = [[0,0],[0,2],[1,1],[2,0],[2,2]]
Output: 3
Example 3:

Input: stones = [[0,0]]
Output: 0
 

Note:

1 <= stones.length <= 1000
0 <= stones[i][j] < 10000
```

## 解题方案

> 思路 1
******- 时间复杂度: O(N^2 * lgN)******- 空间复杂度: O(N)******


贪心，寻找一个点，它对应的row集合里面的点和col对应的集合里面的点加起来最多，这样影响最小

后面发现这样做是错的，去掉当前这个点会影响到它对应集合里面的其他点


```
class Solution:
    def removeStones(self, stones):
        """
        :type stones: List[List[int]]
        :rtype: int
        """
        if not stones or len(stones) <= 1:
            return 0
        rows, cols = collections.defaultdict(set), collections.defaultdict(set)
        for i, j in stones:
            rows[i].add((i,j))
            cols[j].add((i,j))
            
        def helper(stones, rows, cols):
            return all(len(rows[i]) == 1 and len(cols[j]) == 1 for i, j in stones)

        tmp = helper(stones, rows, cols)
        res = 0
        while not tmp:
            stones = [[i,j] for i, j in stones if len(rows[i]) + len(cols[j]) > 2]
            stones = sorted(stones, key = lambda x: len(rows[x[0]])+len(cols[x[1]]))[::-1]
            i, j = stones.pop()
            rows[i].remove((i,j))
            cols[j].remove((i,j))
            tmp = helper(stones, rows, cols)
            res += 1

        return res
```

> 思路 2
******- 时间复杂度: O(N)******- 空间复杂度: O(N)******

参考[cnkyzz](https://leetcode.com/problems/most-stones-removed-with-same-row-or-column/discuss/198141/Python-concise-DFS)

- If you got the idea, question is basically asking for number of islands
- The key point is here, we define an island as number of points that are connected by row or column. Every point does not have to be next to each other.
- Rest is donkey work.

beats 89.61%

```python
class Solution:
    def removeStones(self, stones):
        """
        :type stones: List[List[int]]
        :rtype: int
        """
        def dfs(i, j):
            visited.add((i,j))
            for y in rows[i]:
                if (i, y) not in visited:
                    dfs(i, y)
            for x in cols[j]:
                if (x, j) not in visited:
                    dfs(x, j)
                    
        visited, island = set(), 0
        rows, cols = collections.defaultdict(list), collections.defaultdict(list)
        
        for i, j in stones:
            rows[i].append(j)
            cols[j].append(i)
            
        for i, j in stones:
            if (i, j) not in visited:
                dfs(i, j)
                island += 1
                
        return len(stones) - island
```

> 思路 3
******- 时间复杂度: O(N)******- 空间复杂度: O(N)******


想到用union find，其实就是我们有多少个独立的集合，然后用点的总数减去集合总数就是我们最多可以删除的点，因为我们的目标是使得最终所有的集合中都只有一个点

因为stones里面的点的x坐标和y坐标可能相等，所以我们要注意一下应该使用```union(i, j+10000)```来区分开x坐标和y坐标

beats 48.48%

```python
class UnionFind(object):
    def __init__(self, n):  # 初始化uf数组和组数目
        self.uf = [i for i in range(n)]

    def find(self, x):  # 判断节点所属于的组
        while x != self.uf[x]:
            self.uf[x] = self.uf[self.uf[x]]
            x = self.uf[x]
        return self.uf[x]

    def union(self, x, y):  # 连接两个节点
        x_root = self.find(x)
        y_root = self.find(y)
        if x_root == y_root:
            return
        self.uf[x_root] = y_root
        
        
class Solution:
    def removeStones(self, stones):
        """
        :type stones: List[List[int]]
        :rtype: int
        """
        uf = UnionFind(20000)
        for i, j in stones:
            uf.union(i, j+10000)

        return len(stones) - len({uf.find(i) for i, j in stones})
```

也可以采用dict实现的union-find,但是代码还是不好实现的，参考[寒神](https://www.jianshu.com/p/30d2058db7f7)

beats 72.29%

```python
class Solution:
    def removeStones(self, stones):
        """
        :type stones: List[List[int]]
        :rtype: int
        """
        self.uf = {}
        
        def find(x):
            while x != self.uf[x]:
                self.uf[x] = find(self.uf[x])
                x = self.uf[x]
            return self.uf[x]
        
        def union(x, y):
            self.uf.setdefault(x, x)
            self.uf.setdefault(y, y)
            self.uf[find(x)] = find(y)

        for i, j in stones:
            union(i, ~j)
        return len(stones) - len({find(x) for x in self.uf})
```































