1. 打砖块问题解析与三种解法对比
打砖块问题是一个经典的算法题目,要求我们计算每次击打砖块后会有多少砖块因此掉落。这个问题看似简单,但蕴含着丰富的算法思想和优化技巧。下面我将详细介绍三种不同的解法,并分析它们的优缺点。
1.1 问题描述与核心难点
题目给定一个m×n的网格表示砖块分布,其中1表示有砖块,0表示空白。然后给出一系列击打操作,要求返回一个数组,其中第i个元素表示第i次击打后掉落的砖块数量。
关键点在于:
- 砖块只有与顶部直接或间接相连时才不会掉落
- 击打一个砖块可能导致其他砖块连锁掉落
- 需要高效计算每次击打的影响范围
1.2 并查集解法详解
并查集解法采用逆向思维,先移除所有待击打的砖块,然后逆序补回砖块并计算每次补回时新增的稳定砖块数。
核心步骤如下:
- 预处理阶段:
cpp复制vector<vector<int>> new_grid(grid);
for (auto e : hits)
new_grid[e[0]][e[1]] = 0;
- 构建初始连通域:
cpp复制UD udf(m*n + 1); // 并查集初始化
int root = 0; // 屋顶虚拟节点
for (int i = 0; i < n; ++i) {
if (new_grid[0][i]) {
udf.add(root, tran(0, i)); // 连接顶部砖块
}
}
- 连接剩余砖块:
cpp复制for (int i = 1; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (new_grid[i][j]) {
// 连接左侧和上方砖块
if (j > 0 && new_grid[i][j-1]) {
udf.add(tran(i,j), tran(i, j-1));
}
if (new_grid[i-1][j]) {
udf.add(tran(i, j), tran(i-1,
