Pacific Atlantic Water Flow
The drill: A height grid touches the Pacific along its top and left edges and the Atlantic along its bottom and right edges. Water flows from a cell to a neighbour only when the neighbour's height is less than or equal to its own. Find every cell that can reach both oceans.
A grid of heights represents terrain, with the Pacific Ocean bordering the top and left edges and the Atlantic bordering the bottom and right edges. Water can flow from any cell to an orthogonal neighbor only when that neighbor's height is equal to or lower than the current cell's.
The task is to find every cell from which water could eventually reach both oceans by following that downhill-or-flat rule repeatedly, in any direction the terrain allows.
A cell sitting right on two borders at once already touches both oceans directly. The answer is the full list of such dual-reaching cells, in any order.
- grid up to a couple hundred cells per side
- heights are non-negative integers, ties (equal heights) allowed to flow
- flow direction is 4-directional, always to equal-or-lower ground
- corner cells can touch both oceans directly through their two borders
HINT 1 THE NUDGE
Checking, for every cell, whether it can downhill-flow all the way to both borders is correct but repeats the same downhill paths over and over. What if the search started from the oceans instead?
HINT 2 THE STRUCTURE
Run the flow backwards from the border: from an ocean's edge cells, walk to any neighbour that is equal or taller — the reverse of 'flows to' — and that's exactly the set of cells that can flow down to that ocean.
HINT 3 ONE STEP FROM THE ANSWER
Two multi-source searches, one seeded from every Pacific-edge cell and one from every Atlantic-edge cell, each moving to equal-or-taller neighbours; the answer is every cell visited by both searches.
Heights slope down from a peak of 5 at the top-left to 1 at the bottom-right. Flood backward: from each ocean to a neighbor that's equal or TALLER.
class Solution:
def pacificAtlantic(self, heights: List[List[int]]) -> List[List[int]]:
rows, cols = len(heights), len(heights[0])
pacific = [[False] * cols for _ in range(rows)]
atlantic = [[False] * cols for _ in range(rows)]
def flood(visited, starts):
queue = collections.deque(starts)
for r, c in starts:
visited[r][c] = True
while queue:
r, c = queue.popleft()
for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)):
nr, nc = r + dr, c + dc
if 0 <= nr < rows and 0 <= nc < cols and not visited[nr][nc] and heights[nr][nc] >= heights[r][c]:
visited[nr][nc] = True
queue.append((nr, nc))
pacific_starts = [(r, 0) for r in range(rows)] + [(0, c) for c in range(cols)]
atlantic_starts = [(r, cols - 1) for r in range(rows)] + [(rows - 1, c) for c in range(cols)]
flood(pacific, pacific_starts)
flood(atlantic, atlantic_starts)
return [[r, c] for r in range(rows) for c in range(cols) if pacific[r][c] and atlantic[r][c]]class Solution:
def pacificAtlantic(self, heights: List[List[int]]) -> List[List[int]]:
rows, cols = len(heights), len(heights[0])
def reaches(start_r, start_c, is_pacific):
visited = [[False] * cols for _ in range(rows)]
def dfs(r, c):
if visited[r][c]:
return False
visited[r][c] = True
if is_pacific and (r == 0 or c == 0):
return True
if not is_pacific and (r == rows - 1 or c == cols - 1):
return True
for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)):
nr, nc = r + dr, c + dc
if 0 <= nr < rows and 0 <= nc < cols and heights[nr][nc] <= heights[r][c]:
if dfs(nr, nc):
return True
return False
return dfs(start_r, start_c)
result = []
for r in range(rows):
for c in range(cols):
if reaches(r, c, True) and reaches(r, c, False):
result.append([r, c])
return resultclass Solution {
public int[][] pacificAtlantic(int[][] heights) {
int rows = heights.length, cols = heights[0].length;
boolean[][] pacific = new boolean[rows][cols];
boolean[][] atlantic = new boolean[rows][cols];
Deque<int[]> pQueue = new ArrayDeque<>();
Deque<int[]> aQueue = new ArrayDeque<>();
for (int r = 0; r < rows; r++) {
if (!pacific[r][0]) { pacific[r][0] = true; pQueue.add(new int[]{r, 0}); }
if (!atlantic[r][cols - 1]) { atlantic[r][cols - 1] = true; aQueue.add(new int[]{r, cols - 1}); }
}
for (int c = 0; c < cols; c++) {
if (!pacific[0][c]) { pacific[0][c] = true; pQueue.add(new int[]{0, c}); }
if (!atlantic[rows - 1][c]) { atlantic[rows - 1][c] = true; aQueue.add(new int[]{rows - 1, c}); }
}
flood(heights, pacific, pQueue);
flood(heights, atlantic, aQueue);
List<int[]> result = new ArrayList<>();
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (pacific[r][c] && atlantic[r][c]) result.add(new int[]{r, c});
}
}
return result.toArray(new int[0][]);
}
private void flood(int[][] heights, boolean[][] visited, Deque<int[]> queue) {
int rows = heights.length, cols = heights[0].length;
int[][] dirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
while (!queue.isEmpty()) {
int[] cur = queue.poll();
for (int[] d : dirs) {
int nr = cur[0] + d[0], nc = cur[1] + d[1];
if (nr >= 0 && nr < rows && nc >= 0 && nc < cols && !visited[nr][nc] && heights[nr][nc] >= heights[cur[0]][cur[1]]) {
visited[nr][nc] = true;
queue.add(new int[]{nr, nc});
}
}
}
}
}class Solution {
public int[][] pacificAtlantic(int[][] heights) {
int rows = heights.length, cols = heights[0].length;
List<int[]> result = new ArrayList<>();
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (reaches(heights, r, c, true) && reaches(heights, r, c, false)) {
result.add(new int[]{r, c});
}
}
}
return result.toArray(new int[0][]);
}
private boolean reaches(int[][] heights, int r, int c, boolean pacific) {
boolean[][] visited = new boolean[heights.length][heights[0].length];
return dfs(heights, visited, r, c, pacific);
}
private boolean dfs(int[][] heights, boolean[][] visited, int r, int c, boolean pacific) {
int rows = heights.length, cols = heights[0].length;
if (visited[r][c]) return false;
visited[r][c] = true;
if (pacific && (r == 0 || c == 0)) return true;
if (!pacific && (r == rows - 1 || c == cols - 1)) return true;
int[][] dirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
for (int[] d : dirs) {
int nr = r + d[0], nc = c + d[1];
if (nr >= 0 && nr < rows && nc >= 0 && nc < cols && heights[nr][nc] <= heights[r][c]) {
if (dfs(heights, visited, nr, nc, pacific)) return true;
}
}
return false;
}
}✓ CHIP-TIMED — ALL 4 SOLUTIONS RAN GREEN AGAINST SELF-AUTHORED CASES IN CI · JDK 21 · CPYTHON 3.12 · NOTHING PUBLISHES RED