← DSA
MEDIUM

Pacific Atlantic Water Flow

PracticeNeetCode ↗LeetCode ↗

Given an m × n grid of heights, water flows from a cell to a neighbor whose height is less than or equal to its own, in four directions. The Pacific touches the top and left edges; the Atlantic touches the bottom and right edges. Return every coordinate from which water can reach both oceans.

Example

Input a small heights grid
Output the list of [row, col] cells that drain to both oceans

Key Pointers

Step-by-Step Analysis

  1. Seed two visited sets, pacific and atlantic, from their respective border cells (top row + left column; bottom row + right column).
  2. DFS from each Pacific border cell, only stepping to a neighbor whose height is ≥ the current cell's height — this simulates water flowing backward, uphill, from the ocean.
  3. Repeat the same DFS from each Atlantic border cell into the atlantic set.
  4. Return every coordinate present in both sets.

Complexity

Time: O(rows · cols) — Space: O(rows · cols)

Code

def pacificAtlantic(heights: list[list[int]]) -> list[list[int]]:
    if not heights:
        return []

    rows, cols = len(heights), len(heights[0])
    pacific, atlantic = set(), set()

    def dfs(r: int, c: int, visited: set, prev_height: int) -> None:
        if (r < 0 or r >= rows or c < 0 or c >= cols or
                (r, c) in visited or heights[r][c] < prev_height):
            return
        visited.add((r, c))
        for dr, dc in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
            dfs(r + dr, c + dc, visited, heights[r][c])

    for c in range(cols):
        dfs(0, c, pacific, heights[0][c])
        dfs(rows - 1, c, atlantic, heights[rows - 1][c])

    for r in range(rows):
        dfs(r, 0, pacific, heights[r][0])
        dfs(r, cols - 1, atlantic, heights[r][cols - 1])

    return [[r, c] for r in range(rows) for c in range(cols) if (r, c) in pacific and (r, c) in atlantic]

Code Explanation

How the solution above works, piece by piece.

  1. Reverse the question: start at the ocean edges and move uphill. A cell reached this way can drain back down to that ocean.
  2. dfs stops at the grid edge, at visited cells, or at cells lower than the one it came from (heights[r][c] < prev_height).
  3. Run it from the top row and left column into pacific, and from the bottom row and right column into atlantic.
  4. Return the cells in both sets.
  5. Each cell is visited at most once per ocean: O(rows × cols).

Visual Walkthrough

Running it on an example grid heights = [[1, 2, 3], [8, 9, 4], [7, 6, 5]]:

Cells reachable from each ocean on a 3 by 3 height gridPacific (top/left edge)123894765Atlantic (bottom/right)123894765both123894765answer: [[0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]]
Instead of asking where water flows from each cell, the DFS walks uphill from each ocean's edge (a cell can drain to a neighbour that is lower or equal). The answer is the cells both searches reach.
reaches Pacificreaches Atlantic

Video Explanation

NeetCode — Pacific Atlantic Water Flow, LeetCode 417