417. 太平洋大西洋水流问题


深度优先搜索

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

class Solution {

    int m;
    int n;
    int[][] move = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

    public List> pacificAtlantic(int[][] heights) {

        List> list = new LinkedList<>();

        m = heights.length;
        n = heights[0].length;
        boolean[][] canReachPacific = new boolean[m][n];
        boolean[][] canReachAtlantic = new boolean[m][n];

        /**
         * 类似于《130. 被围绕的区域》的逆向思维
         * 从中间寻找可以同时流到两大洋的数字比较麻烦,但是反过来,从边缘寻找可以逆向流入的数字却比较方便
         * 边缘的第0行和第0列贴近Pacific,所以肯定可以流入;同理第m - 1行和第n - 1列肯定可以流入Atlantic
         */
        for (int i = 0; i < n; i++) {

            dfs(heights, 0, i, canReachPacific);
            dfs(heights, m - 1, i, canReachAtlantic);
        }

        for (int i = 0; i < m; i++) {

            dfs(heights, i, 0, canReachPacific);
            dfs(heights, i, n - 1, canReachAtlantic);
        }

        /**
         * 如果一个数字可以同时被两大洋逆向流入,就记录下坐标
         * Arrays.asList()方法将数组转换为列表
         */
        for (int i = 0; i < m; i++) {

            for (int j = 0; j < n; j++) {

                if (canReachAtlantic[i][j] && canReachPacific[i][j]) {
                    list.add(Arrays.asList(i, j));
                }
            }
        }

        return list;
    }

    /**
     * 所有边缘的数字,以及大于等于前一个且没被遍历过的数字,都能被逆向流入相应的大洋
     */
    public void dfs(int[][] heights, int row, int col, boolean[][] canReach){

        canReach[row][col] = true;

        for (int i = 0; i < 4; i++) {

            int newRow = row + move[i][0];
            int newCol = col + move[i][1];

            if (newRow >= 0 && newRow < m && newCol >= 0 && newCol < n && !canReach[newRow][newCol] && heights[row][col] <= heights[newRow][newCol]) {
                dfs(heights, newRow, newCol, canReach);
            }
        }
    }
}

/**
 * 时间复杂度 O(n)
 * 空间复杂度 O(n)
 */

https://leetcode-cn.com/problems/pacific-atlantic-water-flow/