Featured image of post 803. 打砖块

803. 打砖块

题目描述

有一个 m x n 的二元网格 grid ,其中 1 表示砖块,0 表示空白。砖块 稳定(不会掉落)的前提是:

  • 一块砖直接连接到网格的顶部,或者
  • 至少有一块相邻(4 个方向之一)砖块 稳定 不会掉落时

给你一个数组 hits ,这是需要依次消除砖块的位置。每当消除 hits[i] = (rowi, coli) 位置上的砖块时,对应位置的砖块(若存在)会消失,然后其他的砖块可能因为这一消除操作而 掉落 。一旦砖块掉落,它会 立即 从网格 grid 中消失(即,它不会落在其他稳定的砖块上)。

返回一个数组 result ,其中 result[i] 表示第 i 次消除操作对应掉落的砖块数目。

注意: 消除可能指向是没有砖块的空白位置,如果发生这种情况,则没有砖块掉落。

示例 1:

  • 输入:grid = [[1,0,0,0],[1,1,1,0]], hits = [[1,0]]
  • 输出:[2]
  • 解释:网格开始为:[[1,0,0,0], [1,1,1,0]]
    • 消除 (1,0) 处的砖块,得到网格:[[1,0,0,0], [0,1,1,0]]
    • (1, 1),(1, 2) 这两个砖块不再稳定,因为它们不再与顶部相连,也不再与另一个稳定的砖相邻,因此它们将掉落。得到网格:[[1,0,0,0], [0,0,0,0]]
    • 因此,结果为 [2] 。

示例 2:

  • 输入:grid = [[1,0,0,0],[1,1,0,0]], hits = [[1,1],[1,0]]
  • 输出:[0,0]
  • 解释:网格开始为:[[1,0,0,0], [1,1,0,0]]
    • 消除 (1,1) 处的砖块,得到网格:[[1,0,0,0], [1,0,0,0]]
    • 剩下的砖都很稳定,所以不会掉落。网格保持不变:[[1,0,0,0], [1,0,0,0]]
    • 接下来消除 (1,0) 处的砖块,得到网格:[[1,0,0,0], [0,0,0,0]]
    • 剩下的砖块仍然是稳定的,所以不会有砖块掉落。因此,结果为 [0,0] 。

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 200
  • grid[i][j]01
  • 1 <= hits.length <= 4 * 104
  • hits[i].length == 2
  • 0 <= x <= m - 1
  • 0 <= yi <= n - 1
  • 所有 (xi, yi) 互不相同

解法一:并查集

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
type UnionFind struct {
    parent []int
    // size[i] 表示以 i 为根的树的子节点数目
    size []int
}

func NewUnionFind(n int) *UnionFind {
    uf := &UnionFind{parent: make([]int, n), size: make([]int, n)}
    for i := 0; i < n; i++ {
        uf.parent[i] = i
        uf.size[i] = 1
    }
    return uf
}

func (uf *UnionFind) Find(i int) int {
    if uf.parent[i] != i {
        uf.parent[i] = uf.Find(uf.parent[i])
    }
    return uf.parent[i]
}

func (uf *UnionFind) Merge(i, j int) {
    iF, jF := uf.Find(i), uf.Find(j)
    if iF != jF {
        uf.parent[iF] = jF
        uf.size[jF] += uf.size[iF]
    }
}

func (uf *UnionFind) GetSize(i int) int {
    return uf.size[uf.Find(i)]
}

func hitBricks(grid [][]int, hits [][]int) []int {
    h, w := len(grid), len(grid[0])
    replica := make([][]int, h)
    for i := 0; i < h; i++ {
        replica[i] = make([]int, w)
        copy(replica[i], grid[i])
    }
    for _, hit := range hits {
        i, j := hit[0], hit[1]
        replica[i][j] = 0
    }

    getKey := func(i, j int) int {
        return i*w + j
    }
    size := h * w
    uf := NewUnionFind(size + 1)
    for j := 0; j < w; j++ {
        if replica[0][j] == 1 {
            uf.Merge(size, j)
        }
    }
    for i := 1; i < h; i++ {
        // 不能将 j < w 和 replica[i][j] == 1 这两个条件写在一起,
        // 这样写的后果是如果当忽略两当前行后面的1
        // for j := 0; j < w && replica[i][j] == 1; j++ {
        for j := 0; j < w; j++ {
            if  replica[i][j] == 1 {
                key := getKey(i, j)
                if replica[i-1][j] == 1 {
                    uf.Merge(key, getKey(i-1, j))
                }
                if j >= 1 && replica[i][j-1] == 1 {
                    uf.Merge(key, getKey(i, j-1))
                }
            }
        }
    }

    dirs := [][2]int{{1, 0}, {0, 1}, {-1, 0}, {0, -1}}
    ans := make([]int, len(hits))
    for i := len(hits) - 1; i >= 0; i-- {
        x, y := hits[i][0], hits[i][1]
        if grid[x][y] == 0 {
            continue
        }
        originSize := uf.GetSize(size)
        if x == 0 {
            // 当前要补回的砖块和屋顶相连
            uf.Merge(y, size)
        }
        key := getKey(x, y)
        for _, dir := range dirs {
            // 向四个方向尝试合并
            newX, newY := x+dir[0], y+dir[1]
            if 0 <= newX && newX < h && 0 <= newY && newY < w && replica[newX][newY] == 1 {
                uf.Merge(key, getKey(newX, newY))
            }
        }
        curSize := uf.GetSize(size)
        ans[i] = curSize - originSize - 1
        if ans[i] < 0 {
            ans[i] = 0
        }
        // 不要忘记设置 replica[x][y] = 1
        replica[x][y] = 1
    }
    return ans
}
Licensed under CC BY-NC-SA 4.0
最后更新于 2023/08/11 13:27:04
comments powered by Disqus
Built with Hugo
主题 StackJimmy 设计