1. 题目
给定一个 m x n 的非负整数矩阵来表示一片大陆上各个单元格的高度。“太平洋”处于大陆的左边界和上边界,而“大西洋”处于大陆的右边界和下边界。
规定水流只能按照上、下、左、右四个方向流动,且只能从高到低或者在同等高度上流动。
请找出那些水流既可以流动到“太平洋”,又能流动到“大西洋”的陆地单元的坐标。
提示:
- 输出坐标的顺序不重要
- m 和 n 都小于150
2. 解题思路
这题和130题有点类似,都是从边界往内寻找。
这题呢我们从边界出发,假设先从上边出发,也就是太平洋。 靠近上边的水流一定都可以流入太平洋,那么我们只需要将“上边”遍历,找到高度比它高的,就可以通过它流入太平洋。其它三条边也是这样。只不过右边和下边是可以流入大西洋。
解释一下:题目说高度高的可以向高度低的或者高度相等的流动。 也就是说,只要比上边的水流的高度高,或者相等,那么该水流就可以流到上边,而上边又和太平洋相连,即该水流可流入太平洋。
这样,两轮循环,一轮用来找到可以流入太平洋的水流, 一轮找到可以流入大西洋的水流,把它们分别放入两个boolean数组中,然后再来一次整个数组遍历,如果有一个水流 即可流入太平洋也可流入大西洋(toPa[i][j] && toAt[i][j]
)。那么它就是我们要寻找的。把它的坐标放入res,返回即可。
[!NOTE] 具体操作
我们不是从每个格子出发去判断是否能流到两个海洋(这样每个格子都要进行 DFS,效率低),而是反过来:从太平洋和大西洋的边界出发,向内做 DFS(或 BFS),标记哪些格子能“被水流到”。
具体做法如下:
- 建立两个布尔矩阵
toPa[][]
和toAt[][]
:
toPa[i][j] = true
表示从格子(i,j)
可以逆流到太平洋边界toAt[i][j] = true
表示从格子(i,j)
可以逆流到大西洋边界- 分别从四条边界出发:
- 太平洋边界:第一行 + 第一列
- 大西洋边界:最后一行 + 最后一列
- 对每个边界格子进行 DFS,遵循规则:只有下一个格子的高度 ≥ 当前格子时,才允许逆流过去
- 最后遍历整个矩阵:
- 如果某个格子同时被两个布尔矩阵标记,即可流向两个海洋,加入结果
本题的重点就是 中间的水流可以通过四条边的水流 流入对应的海洋。
[!question] 两个for循环最开始height为什么是Integer最小值?
因为四条边肯定可以流入对应的海洋,所以设置为最小值避免大于四条边的高度
3. 代码
class Solution {
public List<List<Integer>> pacificAtlantic(int[][] matrix) {
List<List<Integer>> res = new ArrayList<>();
if (matrix.length == 0 || matrix[0].length == 0) {
return res;
}
int r = matrix.length; // 行数,可以看成 y 轴
int c = matrix[0].length; // 列数,可以看成 x 轴
boolean[][] toPa = new boolean[r][c];
boolean[][] toAt = new boolean[r][c];
// 太平洋边界:左边界 & 上边界
for (int i = 0; i < r; i++) {
DFS(i, 0, matrix, toPa, Integer.MIN_VALUE); // 左边界
DFS(i, c - 1, matrix, toAt, Integer.MIN_VALUE); // 右边界(大西洋)
}
for (int i = 0; i < c; i++) {
DFS(0, i, matrix, toPa, Integer.MIN_VALUE); // 上边界
DFS(r - 1, i, matrix, toAt, Integer.MIN_VALUE); // 下边界(大西洋)
}
// 遍历整个二维数组,找出能同时到达两个海洋的点
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
if (toPa[i][j] && toAt[i][j]) {
List<Integer> cur = new ArrayList<>();
cur.add(i);
cur.add(j);
res.add(cur);
}
}
}
return res;
}
private void DFS(int r, int c, int[][] matrix, boolean[][] toSea, int height) {
if (r < 0 || r >= matrix.length
|| c < 0 || c >= matrix[0].length
|| toSea[r][c]
|| matrix[r][c] < height) {
return;
}
toSea[r][c] = true;
// 枚举四个方向
DFS(r + 1, c, matrix, toSea, matrix[r][c]);
DFS(r - 1, c, matrix, toSea, matrix[r][c]);
DFS(r, c + 1, matrix, toSea, matrix[r][c]);
DFS(r, c - 1, matrix, toSea, matrix[r][c]);
}
}