题目

有一个 m × n 的矩形岛屿,与 太平洋 和 大西洋 相邻。 “太平洋” 处于大陆的左边界和上边界,而 “大西洋” 处于大陆的右边界和下边界。

这个岛被分割成一个由若干方形单元格组成的网格。给定一个 m x n 的整数矩阵 heights , heights[r][c] 表示坐标 (r, c) 上单元格 高于海平面的高度 。

岛上雨水较多,如果相邻单元格的高度 小于或等于 当前单元格的高度,雨水可以直接向北、南、东、西流向相邻单元格。水可以从海洋附近的任何单元格流入海洋。

返回 网格坐标 result 的 2D列表 ,其中 result[i] = [ri, ci] 表示雨水可以从单元格 (ri, ci) 流向 太平洋和大西洋 。

示例 1: image.png

输入: heights = [[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]]

示例 2:

输入: heights = [[2,1],[1,2]]
输出: [[0,0],[0,1],[1,0],[1,1]]

提示:

m == heights.length
n == heights[r].length
1 <= m, n <= 200
0 <= heights[r][c] <= 10^5

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/pacific-atlantic-water-flow
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

题目很好理解,要求和太平洋、大西洋都连通的坐标点。

如果按常规思路对每一个点417. 太平洋大西洋水流问题 - 图2进行417. 太平洋大西洋水流问题 - 图3遍历,在时间上,有417. 太平洋大西洋水流问题 - 图4个点,每个点要遍历417. 太平洋大西洋水流问题 - 图5时间,时间复杂度为417. 太平洋大西洋水流问题 - 图6#card=math&code=O%28m%5E2%2An%5E2%29&id=ICkhF),会超时。在空间上,除了遍历时常用到的417. 太平洋大西洋水流问题 - 图7数组外,还需要空间记录417. 太平洋大西洋水流问题 - 图8点搜索的结果,即是否同时与太平洋、大西洋都连通。所以需要转变思路。

如果逆向考虑,从边界开始搜索,即分别从太平洋、大西洋进行搜索,分别记录两个水域可以到达的位置,最后返回两个集合的交集即可。重点是,从四个边界分别搜索一遍矩阵,时间复杂度是417. 太平洋大西洋水流问题 - 图9#card=math&code=O%28m%2An%29&id=D6BSj)。

代码

  1. class Solution {
  2. int[][] dirs = {{0, -1}, {0, 1}, {1, 0}, {-1, 0}};
  3. public List<List<Integer>> pacificAtlantic(int[][] heights) {
  4. int m = heights.length;
  5. int n = heights[0].length;
  6. // pacific[i][j] 表示[i,j]这一坐标能否流到太平洋
  7. boolean[][] pacific = new boolean[m][n];
  8. // atlantic[i][j] 表示[i,j]这一坐标能否流到大西洋
  9. boolean[][] atlantic = new boolean[m][n];
  10. for (int i = 0; i < m; i++) {
  11. // 从第一列边界开始搜索,能搜到的位置就表示和太平洋连通,pacific数组可以和下面循环内第一个dfs共用
  12. dfs(i, 0, m, n, heights, pacific);
  13. // 从第n-1列边界开始搜索,能搜到的位置就表示和大西洋连通,atlantic数组可以和下面循环内第二个dfs共用
  14. dfs(i, n - 1, m, n, heights, atlantic);
  15. }
  16. for (int i = 0; i < n; i++) {
  17. // 从第一行边界开始搜索,能搜到的位置就表示和太平洋连通
  18. dfs(0, i, m, n, heights, pacific);
  19. // 从第m-1行边界开始搜索,能搜到的位置就表示和大西洋连通
  20. dfs(m - 1, i, m, n, heights, atlantic);
  21. }
  22. List<List<Integer>> ans = new ArrayList<>();
  23. for (int i = 0; i < m; i++) {
  24. for (int j = 0; j < n; j++) {
  25. // 将和太平洋、大西洋都连通的点添加到结果集
  26. if (pacific[i][j] && atlantic[i][j]) {
  27. ans.add(List.of(i, j));
  28. }
  29. }
  30. }
  31. return ans;
  32. }
  33. private void dfs(int row, int col, int m, int n, int[][] heights, boolean[][] reachable) {
  34. reachable[row][col] = true;
  35. for (int[] dir : dirs) {
  36. int nr = dir[0] + row;
  37. int nc = dir[1] + col;
  38. if (nr < 0 || nr >= m || nc < 0 || nc >= n || reachable[nr][nc] || heights[nr][nc] < heights[row][col]) {
  39. continue;
  40. }
  41. dfs(nr, nc, m, n, heights, reachable);
  42. }
  43. }
  44. }