Pacific Atlantic Water Flow
You're given an m x n grid heights of land elevations. The Pacific Ocean touches the top and left edges, and the Atlantic Ocean touches the bottom and right edges. Rain on a cell can flow to a neighbor up, down, left or right whose height is less than or equal to its own, and any cell on an edge flows straight into the ocean beside it. Return the coordinates [r, c] of every cell whose water can reach both oceans, in any order.
Examples
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]] returns [[0,4],[1,3],[1,4],[2,2],[3,0],[3,1],[4,0]]
Cell [2,2] (height 5) flows up through 3 and 2 to the top edge, reaching the Pacific, and right through 3 and 1 to the right edge, reaching the Atlantic. Corners [0,4] and [4,0] touch both oceans directly.
heights = [[1]] returns [[0,0]]
The only cell touches all four edges, so its water drains into both oceans.
Constraints
- 1 <= m, n <= 200
- 0 <= heights[i][j] <= 10^5
Hints
Instead of asking which cells can reach the oceans, what about starting from the oceans and asking which cells they can reach?
Two BFS / DFS sweeps inward from each ocean's border cells, taking the intersection of reachable cells.
Build pacific and atlantic boolean grids. From every cell touching the Pacific border, DFS to neighbors with heights >= current, marking pacific[r][c] = true. Do the same for the Atlantic border. The answer is every cell true in both grids.
Drill This: Your Approach First
Approach
Rather than tracing downhill paths from every cell, work backwards from the oceans. Start a depth-first search from every Pacific border cell and step only to neighbors at the same height or higher, since water could flow from them back down to you, marking every cell reached. Do the same from the Atlantic border into a second set. Cells in both sets can reach both oceans. Each search visits a cell at most once, so O(m * n) time and space.
Time
O(m * n)
Space
O(m * n)
Pitfall
Solutions
class Solution {
private int m, n;
public List<List<Integer>> pacificAtlantic(int[][] heights) {
m = heights.length; n = heights[0].length;
boolean[][] pac = new boolean[m][n], atl = new boolean[m][n];
for (int i = 0; i < m; i++) {
dfs(heights, i, 0, pac, heights[i][0]);
dfs(heights, i, n - 1, atl, heights[i][n - 1]);
}
for (int j = 0; j < n; j++) {
dfs(heights, 0, j, pac, heights[0][j]);
dfs(heights, m - 1, j, atl, heights[m - 1][j]);
}
List<List<Integer>> result = new ArrayList<>();
for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) {
if (pac[i][j] && atl[i][j]) result.add(Arrays.asList(i, j));
}
return result;
}
private void dfs(int[][] h, int i, int j, boolean[][] visited, int prev) {
if (i < 0 || j < 0 || i >= m || j >= n || visited[i][j] || h[i][j] < prev) return;
visited[i][j] = true;
dfs(h, i + 1, j, visited, h[i][j]);
dfs(h, i - 1, j, visited, h[i][j]);
dfs(h, i, j + 1, visited, h[i][j]);
dfs(h, i, j - 1, visited, h[i][j]);
}
}class Solution:
def pacificAtlantic(self, heights):
if not heights:
return []
m, n = len(heights), len(heights[0])
pac, atl = set(), set()
def dfs(i, j, visited, prev):
if (i, j) in visited or i < 0 or j < 0 or i >= m or j >= n or heights[i][j] < prev:
return
visited.add((i, j))
for di, dj in ((1,0),(-1,0),(0,1),(0,-1)):
dfs(i + di, j + dj, visited, heights[i][j])
for i in range(m):
dfs(i, 0, pac, heights[i][0])
dfs(i, n - 1, atl, heights[i][n - 1])
for j in range(n):
dfs(0, j, pac, heights[0][j])
dfs(m - 1, j, atl, heights[m - 1][j])
return [[i, j] for (i, j) in pac & atl]