Medium
Given an m x n
matrix of non-negative integers representing the height of each unit cell in a continent, the “Pacific ocean” touches the left and top edges of the matrix and the “Atlantic ocean” touches the right and bottom edges.
Water can only flow in four directions (up, down, left, or right) from a cell to another one with height equal or lower.
Find the list of grid coordinates where water can flow to both the Pacific and Atlantic ocean.
Note:
The order of returned grid coordinates does not matter.
Both m and n are less than 150.
Example:
Given the following 5x5 matrix:
Pacific ~ ~ ~ ~ ~
~ 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 *
* * * * * Atlantic
Return:
[[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]]
(positions with parentheses in above matrix).
这道题咋一看去还是会很像number of islands, 目前看到这种题感觉稍微有一些隐隐约约的框架和套路了,肯定是用DFS, 但实施细节还是会有模糊之处。
自己一开始困于如何才能表达matrix[i][j]跟pacific或者是atlantic连接呢,又该怎么表达和两大洋都连接呢? 后来看答案,发现只要分别记录和pacific连接的点与和pacific连接的点,再找到交集就是与两条大洋都连接的点了。 那么问题就只剩下如何表示与某大洋连接呢? 其实我首先脑子里会想到并查集,但是自己没怎么做过union find的题目,所以放弃了。其实我们可以用两个boolean[][]来表示该点是否和pacific, atlantic连接,helper method里的visit[][]既可以理解为我们访问过这个点没有,也可以直接理解成这个点和大洋连接与否。首先我们可以先标记首行尾行,首列尾列,因为他们都是和大洋直接连接的。 然后我们遍历matrix, 找到没有跟大洋连接的点,也就是没有visited过的点,进行DFS遍历。注意到, 我们的helper method里用一个int pre来确保遍历周围的点的时候,出发的点数值是大于等于周围的点的,这样水才可流出去。就很像number of islands里面我们helper method里面遍历出发点周围的四个点,会把周围的岛屿都吃掉,这道题里的“吃掉”就是对应的标记visited[][]为true. 这样的话我们下次就不会再遍历该点,并且可以确定该点是不是跟大洋连接起来了。
class Solution {
public int m;
public int n;
public List<int[]> pacificAtlantic(int[][] matrix) {
List<int[]> res = new ArrayList<>();
if (matrix == null || matrix.length == 0 || matrix[0].length == 0){
return res;
}
m = matrix.length;
n = matrix[0].length;
boolean[][] pacific = new boolean[m][n];
boolean[][] atlantic = new boolean[m][n];
for (int i = 0; i < m; i++){
helper(matrix, pacific, Integer.MIN_VALUE, i, 0);
helper(matrix, atlantic, Integer.MIN_VALUE, i, n - 1);
}
for (int i = 0; i < n; i++){
helper(matrix, pacific, Integer.MIN_VALUE, 0, i);
helper(matrix, atlantic, Integer.MIN_VALUE, m - 1, i);
}
for (int i = 0; i < m; i++){
for (int j = 0; j < n; j++){
if (pacific[i][j] && atlantic[i][j]){
res.add(new int[]{i,j});
}
}
}
return res;
}
private void helper(int[][] matrix, boolean[][] visited, int pre, int i, int j){
if (i < 0 || i >= m || j < 0 || j >= n || visited[i][j] || matrix[i][j] < pre){
return;
}
visited[i][j] = true;
helper(matrix, visited, matrix[i][j], i - 1, j);
helper(matrix, visited, matrix[i][j], i, j - 1);
helper(matrix, visited, matrix[i][j], i + 1, j);
helper(matrix, visited, matrix[i][j], i, j + 1);
}
}