集水器
难度:
标签:
题目描述
English description is not available for the problem. Please switch to Chinese.
代码结果
运行时间: 147 ms, 内存: 17.6 MB
/*
* 思路:
* 1. 从上至下扫描矩阵,找到所有未闭合的区域,并标记这些区域。
* 2. 通过深度优先搜索(DFS)标记出所有与未闭合区域相连的点。
* 3. 使用 Java Stream 计算所有未标记的区域的水量,每个未标记的点代表 2 个单位的水量。
*/
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class WaterContainerStream {
public int calculateWaterVolume(String[] shape) {
int rows = shape.length;
int cols = shape[0].length();
boolean[][] visited = new boolean[rows][cols];
IntStream.range(0, rows).forEach(i -> {
IntStream.range(0, cols).forEach(j -> {
if (shape[i].charAt(j) == '.' && (i == 0 || i == rows - 1 || j == 0 || j == cols - 1)) {
dfs(shape, visited, i, j);
}
});
});
return (int) IntStream.range(0, rows)
.mapToLong(i -> IntStream.range(0, cols)
.filter(j -> !visited[i][j] && shape[i].charAt(j) == '.')
.count() * 2)
.sum();
}
private void dfs(String[] shape, boolean[][] visited, int x, int y) {
int rows = shape.length;
int cols = shape[0].length();
if (x < 0 || x >= rows || y < 0 || y >= cols || visited[x][y] || shape[x].charAt(y) != '.') {
return;
}
visited[x][y] = true;
int[] dx = {-1, 1, 0, 0};
int[] dy = {0, 0, -1, 1};
for (int i = 0; i < 4; i++) {
dfs(shape, visited, x + dx[i], y + dy[i]);
}
}
}
解释
方法:
此题解通过模拟和并查集技术解决集水器问题。每个格子被划分为四个部分(上下左右),用于表示格子中的不同隔板区域。题解策略是通过并查集维护这些部分之间的连通性。首先,题解为每个格子的四个部分分配了唯一的标识符,然后根据格子的隔板类型('l', 'r', 或 '.'),在相应的部分之间建立连接。此外,所有格子的左右边界部分被连接到一个超级汇点,以表示外部空间。然后通过逐行逆向遍历,并查集来判断每个部分是否可以容纳水(即检查该部分是否与外部空间连通)。最后,统计所有可以容纳水的部分,每部分记为2单位水量,然后求出总水量。
时间复杂度:
O(n * m)
空间复杂度:
O(n * m)
代码细节讲解
🦆
在并查集中,如何处理超级汇点与格子边界部分的连接,以及这种连接方式对算法结果的影响是什么?
▷🦆
题解中提到的逆向遍历格子的原因是什么?直接正向遍历有什么潜在的问题或不足?
▷🦆
并查集中的`merge`操作是如何确保隔板类型正确影响到格子部分的连通性的?具体是如何根据隔板的类型`'l'`, `'r'`, `'.'`来决定合并哪些部分?
▷