基本資料#
難易度: medium 第一次嘗試: 2025-05-10
- 總花費時間:20:00.00
解題思路#
移除石頭的條件是:在同一列或同一欄有其他石頭存在。
因此,我們可以使用並查集(Union Find)將具有相同 x 或 y 座標的石頭歸為同一組。
分組完成後,每一組都可以移除 (組大小 - 1) 顆石頭,總和即為結果。
一開始我嘗試用最大座標值來初始化 parent 陣列,但遇到 MLE(記憶體超出限制),因為若有一個離群的座標 k,就會從 1 ~ k 分配大量不必要的記憶體。
為了解決這個問題,我改用字典作為 parent 結構,並將每個座標轉成字串(例如 "x,y")作為 key 來處理。
解法#
Basic Union Find#
class Solution:
    def removeStones(self, stones: List[List[int]]) -> int:
        parents = {}
        def find(x):
            if parents.get(x, x) != x:
                parents[x] = find(parents[x])
            else:
                parents[x] = x
            return parents[x]
        def union(x, y):
            root_x = find(x)
            root_y = find(y)
            if root_x == root_y:
                return 
            parents[root_x] = parents[root_y]
        for x in stones:
            for y in stones:
                if x == y:
                    continue
                if x[0] == y[0] or x[1] == y[1]:
                    coordinate_x = ",".join(map(str, x))
                    coordinate_y = ",".join(map(str, y))
                    union(coordinate_x, coordinate_y)
        seen = set()
        res = 0
        for stone in stones:
            coordinate = ",".join(map(str, stone))
            group = find(coordinate)
            if group in seen:
                res += 1
            else:
                seen.add(group)
        return res
Optimize Union Find#
這題的精髓在於:將二維座標扁平化為一維的 Union Find 結構。
我一開始嘗試用 "x,y" 字串當作 key,但這導致需要雙層迴圈(時間複雜度 O(n²)),且在座標稀疏或很大的情況下會造成記憶體浪費。
後來我學到一個更聰明的做法:將 row 和 column index 統一在同一個 1D 鍵值空間。
具體做法是,row 用原本的 x,column 則取 ~y(位元反轉)來避免與 x 衝突。
這個方法的思路是:把每顆石頭視為連接一個 row index 和一個 column index 的節點。
如果兩顆石頭在同一 row 或 column,則它們對應的 index 就會被 Union 起來。
最後統計有幾個獨立的群組(也就是「島嶼」數量),因為每個群組至少要保留一顆石頭不被移除。
所以最終答案為:總石頭數 - 群組數量(島嶼數)
以下是這種做法的簡潔 Python 實作:
class Solution:
    def removeStones(self, stones: List[List[int]]) -> int:
        parent = {}
        def find(x):
            if x != parent.setdefault(x, x):
                parent[x] = find(parent[x])
            return parent[x]
        def union(x, y):
            parent[find(x)] = find(y)
        for x, y in stones:
            union(x, ~y)
        return len(stones) - len({find(x) for x in parent})
收穫#
遇到的問題#
一開始我用 f"{x}{y}" 來生成座標字串,但這樣會產生碰撞問題。
例如 [12, 3] 和 [1, 23] 都會變成 "123"。
為了解決這個問題,我改用逗號分隔的方式來產生唯一的 key(例如 "12,3")。

