leet-code/src/main/java/leetcode/editor/cn/PacificAtlanticWaterFlow.java

119 lines
4.7 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//给定一个 m x n 的非负整数矩阵来表示一片大陆上各个单元格的高度。“太平洋”处于大陆的左边界和上边界,而“大西洋”处于大陆的右边界和下边界。
//
// 规定水流只能按照上、下、左、右四个方向流动,且只能从高到低或者在同等高度上流动。
//
// 请找出那些水流既可以流动到“太平洋”,又能流动到“大西洋”的陆地单元的坐标。
//
//
//
// 提示:
//
//
// 输出坐标的顺序不重要
// m 和 n 都小于150
//
//
//
//
// 示例:
//
//
//
//
//给定下面的 5x5 矩阵:
//
// 太平洋 ~ ~ ~ ~ ~
// ~ 1 2 2 3 (5) *
// ~ 3 2 3 (4) (4) *
// ~ 2 4 (5) 3 1 *
// ~ (6) (7) 1 4 5 *
// ~ (5) 1 1 2 4 *
// * * * * * 大西洋
//
//返回:
//
//[[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] (上图中带括号的单元).
//
//
//
// Related Topics 深度优先搜索 广度优先搜索 数组 矩阵
// 👍 274 👎 0
package leetcode.editor.cn;
import java.util.ArrayList;
import java.util.List;
//417:太平洋大西洋水流问题
class PacificAtlanticWaterFlow {
public static void main(String[] args) {
//测试代码
Solution solution = new PacificAtlanticWaterFlow().new Solution();
}
//力扣代码
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {// 用来返回的返回值
private final List<List<Integer>> ans = new ArrayList<>();
// 方向转换的数组
private final int[][] dirs = {{0, -1}, {1, 0}, {0, 1}, {-1, 0}};
// 大西洋和太平洋共享的访问数组
private boolean[][] visited = null;
public List<List<Integer>> pacificAtlantic(int[][] heights) {
int n = heights.length, m = heights[0].length;
visited = new boolean[n][m];
// temp 是用来记录当前深度优先搜索访问过的点
boolean[][] temp = new boolean[n][m];
// 首先从太平洋出发,看看都能遇到哪些点
for (int x = 0; x < n; ++x) {
for (int y = 0; y < m; ++y) {
// x == 0 || y == 0 表示要从太平洋出发需要满足的条件flag == false 意味着是从太平洋出发的
if ((x == 0 || y == 0) && !temp[x][y]) dfs(heights, x, y, temp, n, m, false);
}
}
// 同上temp 是用来标记当前深度优先搜索访问到的点
temp = new boolean[n][m];
// 然后再从大西洋出发,看看能遇到哪些点,如果遇到的点 在 visited 中之前已经被标记为 true 那么说明双方都可到达
for (int x = 0; x < n; ++x) {
for (int y = 0; y < m; ++y) {
// x == n - 1 || y == m - 1 表示从大西洋出发
if ((x == n - 1 || y == m - 1) && !temp[x][y]) dfs(heights, x, y, temp, n, m, true);
}
}
return ans;
}
/**
* @param x 深度优先搜索的起始点坐标 x
* @param y 起始点坐标 y
* @param temp 用来标记当前深度优先搜索已经访问过哪些点了
* @param flag 为 true 时意味着是大西洋来的,为 false 意味着是太平洋来的
*/
private void dfs(int[][] heights, int x, int y, boolean[][] temp, int n, int m, boolean flag) {
// 如果是大西洋来的,而且 太平洋已经访问过 {x, y} 了,就放到返回值中
if (flag && visited[x][y]) {
List<Integer> buf = new ArrayList<>();
buf.add(x);
buf.add(y);
ans.add(buf);
// 顺便把该点置为 false防止重复记录
visited[x][y] = false;
}
// 如果是从太平洋来的,需要将 {x, y} 标记为已来过
if (!flag) visited[x][y] = true;
// 然后切换四个方向,逐个检查
for (int i = 0; i < 4; ++i) {
int nx = x + dirs[i][0];
int ny = y + dirs[i][1];
// 检查新的坐标是否合法,以及当前深度优先搜索是否来过,最后还要满足 逆向 条件
if (nx >= 0 && nx < n && ny >= 0 && ny < m && !temp[nx][ny] && heights[nx][ny] >= heights[x][y]) {
temp[nx][ny] = true; // 然后在当前深度优先搜索中标记为已来过
dfs(heights, nx, ny, temp, n, m, flag); // 继续深度优先搜索
}
}
}
}
//leetcode submit region end(Prohibit modification and deletion)
}