LeetCode题解(0803):打砖块(Python)

本文介绍了一种利用并查集数据结构解决题目中砖块碰撞问题的Python实现,详细解析了时间复杂度为O(N+H),空间复杂度为O(N)的方法,并讨论了不同解法的执行效率。通过实例演示和代码展示,帮助读者理解并查集在解决此类问题中的应用。
摘要由CSDN通过智能技术生成

题目:原题链接(困难)

标签:并查集

解法时间复杂度空间复杂度执行用时
Ans 1 (Python) O ( N + H ) O(N+H) O(N+H) O ( N ) O(N) O(N)1504ms (7.69%)
Ans 2 (Python)
Ans 3 (Python)

解法一:

class DSU2:
    def __init__(self):
        self._n = 0
        self._parent = {}
        self._size = {}

    def add(self, i):
        if i not in self._parent:
            self._parent[i] = i
            self._size[i] = 1

    def get_size(self, i):
        return self._size[self.find(i)]

    def find(self, i):
        if self._parent[i] != i:
            self._parent[i] = self.find(self._parent[i])
        return self._parent[i]

    def union(self, i, j):
        i, j = self.find(i), self.find(j)
        if i != j:
            self._parent[i] = j
            self._size[j] += self._size[i]
            del self._size[i]

    def is_connected(self, x, y):
        return self.find(x) == self.find(y)


class Solution:
    _CEIL = (-1, -1)
    _DIRECTION = ((1, 0), (-1, 0), (0, 1), (0, -1))

    def hitBricks(self, grid: List[List[int]], hits: List[List[int]]) -> List[int]:
        def is_valid(xx, yy):
            return 0 <= xx < m and 0 <= yy < n and grid[xx][yy] == 1

        def merge_neighbors(x1, y1):
            """合并周围的砖"""
            for dx, dy in self._DIRECTION:
                x2, y2 = x1 + dx, y1 + dy
                if is_valid(x2, y2):
                    dsu.union((x1, y1), (x2, y2))

        m, n = len(grid), len(grid[0])

        # 构造并查集
        dsu = DSU2()

        # 将天花板添加到并查集中
        dsu.add(self._CEIL)

        # 敲掉所有会被敲掉的砖块
        for (i, j) in hits:
            grid[i][j] -= 1

        # 将剩余的砖块添加到并查集中
        for i in range(m):
            for j in range(n):
                if grid[i][j] == 1:
                    dsu.add((i, j))

        # 合并不会被桥段的砖块
        for i in range(m):
            for j in range(n):
                if grid[i][j] == 1:
                    merge_neighbors(i, j)

        # 将顶部砖块与天花板合并
        for j in range(n):
            if grid[0][j] == 1:
                dsu.union((0, j), self._CEIL)

        ans = [0] * len(hits)

        # 处理敲击的情况
        for k in range(len(hits) - 1, -1, -1):
            i, j = hits[k][0], hits[k][1]

            # 敲完以后与天花板连接的数量
            after_hit = dsu.get_size(self._CEIL)

            # 还原被敲掉的砖块
            grid[i][j] += 1
            if grid[i][j] != 1:  # 处理砖块已经被敲过的情况
                continue
            dsu.add((i, j))

            merge_neighbors(i, j)
            if i == 0:
                dsu.union((i, j), self._CEIL)

            # 被敲的地方和天花板连接
            if dsu.is_connected((i, j), self._CEIL):
                # 敲之前和天花板连接的数量
                before_hit = dsu.get_size(self._CEIL)
                ans[k] = (before_hit - after_hit - 1)

        return ans
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值