#417 Pacific Atlantic Water Flow
the problem
In plain words
heights is an island. The Pacific touches the top and left edges; the Atlantic the bottom and right. Water flows to a neighbour with height ≤ the current one. Return every cell from which water can reach both oceans.
in 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]]
out [[0,4],[1,3],[1,4],[2,2],[3,0],[3,1],[4,0]]
in heights = [[1]]
out [[0,0]]
- 1 ≤ m, n ≤ 200
- 0 ≤ heights[r][c] ≤ 10⁵
your turn
Try it before you peek
Read the examples, say the brute force out loud, then write code: here or on LeetCode ↗. Stuck for 20 minutes? Open one hint at a time.
Solve it in the browser
LeetCode-style: complete the class. Compiled by the real javac (Java 17) and judged right here — nothing is sent anywhere.
Solutions are hidden so you can try first. Even 20 minutes of real effort makes the answer stick far better than reading it.
Marking the problem solved, or opening every hint, also shows it.
the aha
Key insight
patternReverse search from the borderMulti-source BFS
Asking "where can water from this cell go?" for every cell is slow. Ask the reverse: "which cells can the ocean climb up to?" Two searches, one per ocean, then intersect.
solutions
From brute force to optimal
For each cell, DFS to lower-or-equal neighbours and record which edges it touches.
- For each cell, run a fresh DFS with its own visited array.
- Touching row 0 / col 0 → Pacific; last row / last col → Atlantic.
- Keep cells that reach both.
m·n searches, each up to m·n cells.
Visited array and recursion for one search.
class Solution { private static final int[][] DIRS = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; /** From every cell, flood "downhill" and see which oceans the water can reach. */ public List<List<Integer>> pacificAtlantic(int[][] heights) { int rows = heights.length, cols = heights[0].length; List<List<Integer>> result = new ArrayList<>(); for (int r = 0; r < rows; r++) for (int c = 0; c < cols; c++) { boolean[] oceans = new boolean[2]; // [0] = Pacific, [1] = Atlantic flow(heights, r, c, new boolean[rows][cols], oceans); if (oceans[0] && oceans[1]) result.add(List.of(r, c)); } return result; } private void flow(int[][] h, int r, int c, boolean[][] seen, boolean[] oceans) { seen[r][c] = true; if (r == 0 || c == 0) oceans[0] = true; // top or left edge if (r == h.length - 1 || c == h[0].length - 1) oceans[1] = true; // bottom or right edge for (int[] d : DIRS) { int nr = r + d[0], nc = c + d[1]; if (nr < 0 || nc < 0 || nr >= h.length || nc >= h[0].length || seen[nr][nc]) continue; if (h[nr][nc] <= h[r][c]) flow(h, nr, nc, seen, oceans); // water runs to lower or equal } }}Multi-source DFS from each ocean's border cells, moving only to higher-or-equal neighbours.
- DFS from every Pacific border cell into
pacific[][]. - DFS from every Atlantic border cell into
atlantic[][]. - Answer = cells marked in both.
Each cell is marked at most once per ocean.
Two boolean grids plus recursion depth.
class Solution { private static final int[][] DIRS = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; /** Reverse the flow: climb UP from each ocean's shore; answer = cells both oceans can climb to. */ public List<List<Integer>> pacificAtlantic(int[][] heights) { int rows = heights.length, cols = heights[0].length; boolean[][] pacific = new boolean[rows][cols], atlantic = new boolean[rows][cols]; for (int r = 0; r < rows; r++) { climb(heights, r, 0, pacific); climb(heights, r, cols - 1, atlantic); } for (int c = 0; c < cols; c++) { climb(heights, 0, c, pacific); climb(heights, rows - 1, c, atlantic); } List<List<Integer>> 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(List.of(r, c)); return result; } private void climb(int[][] h, int r, int c, boolean[][] reach) { if (reach[r][c]) return; reach[r][c] = true; for (int[] d : DIRS) { int nr = r + d[0], nc = c + d[1]; if (nr < 0 || nc < 0 || nr >= h.length || nc >= h[0].length) continue; if (h[nr][nc] >= h[r][c]) climb(h, nr, nc, reach); // uphill or flat only } }}in the room
How to say it in the interview
talk track
- Lead with the reversal: "water flows down from a cell ⇔ the ocean can climb up to that cell."
traps
- Flipping the comparison the wrong way when reversing: going up means
h[next] >= h[cur]. - Forgetting that equal heights let water flow.
what they ask next
Follow-ups
The grid is 10⁴ × 10⁴ — will the recursive climb survive?
Not in Java: a flat region makes the recursion as deep as the region. Run the same climb as a multi-source BFS — seed the queue with every shore cell of one ocean.
before you submit
Edge cases to test
- A single cell touches both oceans → [[0,0]].
- A flat grid: every cell reaches both oceans.
- A pit lower than all its neighbours drains nowhere — unless it is on the shore.
practise next
Similar problems
- #130Surrounded RegionsMediumin Graphs
- #200Number of IslandsMediumin Graphs
- #329Longest Increasing Path in a MatrixHardin Topo Sort