1. 程式人生 > >Leetcode 947:移除最多的同行或同列石頭(超詳細的解法!!!)

Leetcode 947:移除最多的同行或同列石頭(超詳細的解法!!!)

在二維平面上,我們將石頭放置在一些整數座標點上。每個座標點上最多隻能有一塊石頭。
現在,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

如有問題,希望大家指出!!!