Leetcode 947:移除最多的同行或同列石头(超详细的解法!!!)

版权声明:本文为博主原创文章,未经博主允许不得转载。有事联系:[email protected] https://blog.csdn.net/qq_17550379/article/details/84993657

在二维平面上,我们将石头放置在一些整数坐标点上。每个坐标点上最多只能有一块石头。
现在,move 操作将会移除与网格上的某一块石头共享一列或一行的一块石头。
我们最多能执行多少次 move 操作?

示例 1:

输入:stones = [[0,0],[0,1],[1,0],[1,2],[2,1],[2,2]]
输出:5

示例 2:

输入:stones = [[0,0],[0,2],[1,1],[2,0],[2,2]]
输出:3

示例 3:

输入:stones = [[0,0]]
输出:0

提示:

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

解题思路

这个问题我拿到手首先想到的处理思路就是并查集。我们可以通过并查集很快的确定哪些元素是横坐标或者纵坐标联通(也就是确定一个集合)。我们最后的结果就是每个集合中只存放一个元素,取出其余元素。

class Solution:
    def removeStones(self, stones):
        """
        :type stones: List[List[int]]
        :rtype: int
        """
        stones = list(map(tuple, stones))
        stones_len = len(stones)
        uf = collections.defaultdict()
        count = stones_len
        for c in stones:
            uf[c] = c
            
        def find(coor):
            if coor != uf[coor]:
                uf[coor] = find(uf[coor])
            return uf[coor]
        
        def union(c1, c2):
            nonlocal count
            p1, p2 = find(c1), find(c2)
            if p1 == p2:
                return
            
            uf[p1] = c2
            count -= 1
            
        for c1, c2 in itertools.combinations(stones, 2):
            if c1[0] == c2[0] or c1[1] == c2[1]:
                union(c1, c2)

        return stones_len - count

实际上我们这个代码实现的非常不好。我们使用combinations这个函数,这样我们的遍历次数增加了许多。我们能不能只遍历一遍就知道结果呢?我们实际上可以不通过合并点,而是通过合并xy坐标实现,但是xy坐标有很多相同的元素要怎么办呢?我们要知道我们通过归并点的本质其实是想要区分xy坐标,所以我们在归并xy坐标的时候也要将其区分,一个简单的思路就是对y取逆。

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

        for i, j in stones:
            union(i, ~j)
        return len(stones) - len({find(x) for x in UF})

有了前面的思路我们不难想到这其实就是一个寻找岛屿数量的问题,通过深度优先遍历找到岛屿的个数。

from collections import defaultdict
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, rows, cols = set(), 0, defaultdict(list), 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

最后的结果就是stones的数量减去岛屿的数量。

reference:

https://leetcode.com/problems/most-stones-removed-with-same-row-or-column/discuss/197668/Count-the-Number-of-Islands-O(N)

我将该问题的其他语言版本添加到了我的GitHub Leetcode

如有问题,希望大家指出!!!

猜你喜欢

转载自blog.csdn.net/qq_17550379/article/details/84993657