打砖块
难度:
标签:
题目描述
代码结果
运行时间: 167 ms, 内存: 23.2 MB
/*
* Solution approach using Java Streams:
* Similar to the previous solution but leveraging Java Streams for iteration and collection operations.
*/
import java.util.*;
import java.util.stream.*;
public class SolutionStream {
public int[] hitBricks(int[][] grid, int[][] hits) {
int m = grid.length, n = grid[0].length;
Arrays.stream(hits).forEach(hit -> grid[hit[0]][hit[1]] -= 1);
IntStream.range(0, n).forEach(j -> dfs(grid, 0, j));
int[] res = new int[hits.length];
IntStream.range(0, hits.length).map(i -> hits.length - 1 - i).forEach(i -> {
int r = hits[i][0], c = hits[i][1];
grid[r][c] += 1;
if (grid[r][c] == 1 && isConnectedToTop(grid, r, c)) {
res[i] = dfs(grid, r, c) - 1;
}
});
return res;
}
private int dfs(int[][] grid, int r, int c) {
if (r < 0 || r >= grid.length || c < 0 || c >= grid[0].length || grid[r][c] != 1) {
return 0;
}
grid[r][c] = 2;
return 1 + IntStream.of(new int[]{1, -1}).map(d -> dfs(grid, r + d, c) + dfs(grid, r, c + d)).sum();
}
private boolean isConnectedToTop(int[][] grid, int r, int c) {
if (r == 0) {
return true;
}
return Stream.of(new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}).anyMatch(dir -> {
int x = r + dir[0], y = c + dir[1];
return x >= 0 && x < grid.length && y >= 0 && y < grid[0].length && grid[x][y] == 2;
});
}
}
解释
方法:
这道题的思路是使用并查集和逆向思维。首先,我们将所有的hit操作预先执行,将对应位置的砖块标记为已消除状态。然后从网格的顶部开始进行深度优先搜索,将所有与顶部连通的砖块标记为稳定状态。接下来,我们逆序遍历hits数组,依次将砖块还原。对于每个还原的砖块,我们判断其是否与稳定的砖块相邻或者位于顶部,如果是,则进行深度优先搜索,将与其连通的不稳定砖块都标记为稳定状态,并记录下变为稳定状态的砖块数量。最后返回每次还原操作导致掉落的砖块数量。
时间复杂度:
O(l * nm)
空间复杂度:
O(nm)
代码细节讲解
🦆
为什么在处理结束后,需要将grid中的值从1改为2来标记砖块为稳定状态?这与原始的1有何不同?
▷🦆
在预处理`hits`数组时,为何直接将grid中的值减1而不是检查当前位置是否有砖块存在?
▷🦆
在计算每次还原操作导致的掉落砖块数量时,为什么要从结果中减去1?
▷🦆
递归深度优先搜索(DFS)中,如何处理grid边界外的情况以及避免重复访问已标记为稳定的砖块?
▷