Understand
30-second explanation
Build the interview-ready mental model before comparing implementations.
Don't simulate flow from every cell — reverse it. Start from the ocean border cells and climb to neighbours of equal or greater height, marking which cells can reach the Pacific and which can reach the Atlantic. The answer is the intersection: cells reachable from both oceans. Two flood fills over the grid → O(rows × cols).
Interview contextWhat is testedWhere candidates slipHow to stand outExplore interview contextHide interview context
What's being tested
Whether you avoid the O((mn)²) brute force by reversing the flow and seeding multi-source traversals from the borders, then intersecting two reachability sets.
Where candidates slip
Running a separate flow simulation from every cell (quadratic), using `>` instead of `>=`, or only seeding from corners instead of entire border rows/columns.
How to stand out
Explain the reversal insight crisply ('climb from the ocean'), seed both border sets, use a visited matrix per ocean, intersect, and note BFS works identically if recursion depth is a concern.
Choose
Compare the available approaches
Use constraints and trade-offs to select the route you can defend in an interview.
Interactive decision treeInteractiveChoose the right approachFirst decision previewCells draining to both oceansSimulate from each cell?Brute forceReverse itExplore the full treeCollapse the tree
Learn & trace
Build each solution step by step
Move from the core idea to a visual trace, implementation, proof, and edge cases.
Approach 1 of 2
Brute Force — Flow Simulation From Every Cell
1Hint 1Explore hintHide hint
Literal reading: for each cell, can water flow downhill from it all the way to each ocean?
2Hint 2Explore hintHide hint
From each starting cell, DFS/BFS following non-increasing heights; record whether you reach a Pacific border and whether you reach an Atlantic border.
3Hint 3Explore hintHide hint
A cell qualifies if a single search from it touches both. But you'd repeat this search from all m·n cells — that's the bottleneck.
A · Core idea
Translate the problem directly: a cell drains to an ocean if a downhill (non-increasing) path leads from it to that ocean's edge.
Per-cell search. For each cell, run a DFS/BFS that only steps to neighbours with height ≤ the current cell's height (the natural flow direction). Flag whether the search ever lands on a Pacific border and whether it lands on an Atlantic border. If both, add the cell to the answer.
Why it's too slow. You repeat an O(m·n) traversal from every one of the m·n cells, giving O((m·n)²) — roughly 1.6 billion operations on a 200×200 grid. Correct but not acceptable. The waste is obvious: the same downhill paths get re-explored from many starting points. That redundancy is the cue to flip the direction of the search.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
heights = [[2,1],[1,2]](0,0)=2
borders both Pacific(top/left); also can it reach Atlantic? downhill to (0,1)=1,(1,0)=1
reaches both[[0,0],[0,1],[1,0],[1,1]]C · Code with teaching comments
Reference implementation preview// Illustrative only — O((m*n)^2), too slow for the constraints. public List<List<Integer>> pacificAtlantic(int[][] heights) { int m = heights.length, n = heights[0].length; List<List<Integer>> res = new ArrayList<>(); for (int r = 0; r < m; r++) {Explore the full codeHide the full code
D · Why it works and complexityO((m × n)²) timeO(m × n) spaceOpen the invariant and proofExplore the proofHide the proof
When 'can X reach a target?' must be answered for many X but few targets, invert it: compute 'what can each target reach?' once per target. Here there are only two targets (the two oceans) but thousands of cells — so two reverse searches crush thousands of forward ones.
ComplexityO((m × n)²) time, O(m × n) space — Each of the m·n cells launches a traversal that can visit up to m·n cells → O((m·n)²). The visited bookkeeping per search is O(m·n) space.
E · Edge cases and pitfalls3Re-running a full traversal per cell — quadratic and times out at 200×200.Explore edge casesHide edge cases
Pitfalls
- Re-running a full traversal per cell — quadratic and times out at 200×200.
- Resetting the visited structure incorrectly between cells.
- Confusing flow direction (should be downhill, neighbour ≤ current, in the forward simulation).
Approach 2 of 2 · Optimal
Reverse Multi-Source DFS From Both Oceans (Optimal)
1Hint 1Explore hintHide hint
Flip the question. Instead of 'which cells reach the ocean?', ask 'which cells can the ocean reach if water flowed backward (uphill)?'
2Hint 2Explore hintHide hint
Seed a DFS from every Pacific border cell (top row + left column) and climb to neighbours with height ≥ current, marking a `pacific` set. Do the same from the Atlantic borders into an `atlantic` set.
3Hint 3Explore hintHide hint
Any cell in both sets can drain to both oceans. Intersect the two visited sets for the answer.
A · Core idea
The whole problem cracks open once you reverse the flow.
The reversal insight. Water flows from high to low. A cell drains to the Pacific iff there's a non-increasing path from it to a Pacific border. Equivalently, starting at a Pacific border and walking to neighbours that are higher or equal, you can reach exactly those cells that drain into the Pacific. So instead of n thousand downhill searches, we do one uphill search seeded from the ocean.
Two multi-source traversals. Seed a DFS (or BFS) with all Pacific border cells at once — the entire top row and left column — and flood inward, only stepping to a neighbour whose height is >= current. Every cell reached lands in the pacific set. Repeat from the Atlantic borders (bottom row + right column) into the atlantic set. 'Multi-source' just means we start the search from many seeds simultaneously rather than restarting per seed.
Intersect. A cell that appears in both sets can drain to both oceans — that's the answer. Walk the grid once and collect cells present in both visited matrices.
Why `>=` not `>`. Forward flow is allowed when the neighbour is ≤ current, which includes equal heights. Reversing, we move from current to a neighbour that is ≥ current — and equal-height neighbours must still be traversable, so the comparison is >=.
B · Visual dry run
Interactive dry run
Select a frame to connect the decision with its visual state.
heights = [[1,2,2,3,5],[3,2,3,4,4],...] (5×5 sample)Array state
pacific
reach from top/left
[[0,4],[1,3],[1,4],[2,2],[3,0],[3,1],[4,0]]C · Code with teaching comments
D · Why it works and complexityO(m × n) timeO(m × n) spaceOpen the invariant and proofExplore the proofHide the proof
Two reverse floods replace tens of thousands of forward ones. The trick generalises: whenever the targets are few and the sources are many, search backward from the targets. Marking visited per ocean (not globally) is essential — a cell can belong to both reachable sets.
ComplexityO(m × n) time, O(m × n) space — Each ocean's traversal visits every cell at most once (a per-ocean visited matrix), so each is O(m·n); two of them is still O(m·n). The two visited matrices are O(m·n) space.
E · Edge cases and pitfalls6single cell [[1]] — Borders all edges; in both sets → [[0,0]].Explore edge casesHide edge cases
Edge cases handled
single cell [[1]]Borders all edges; in both sets → [[0,0]].single rowLeft end seeds Pacific, right end seeds Atlantic; intersection where climbs overlap.flat grid (all equal)`>=` lets water traverse everywhere; every cell reaches both oceans.
Pitfalls
- Using `>` instead of `>=` — equal-height cells wrongly block the climb.
- A single shared visited matrix for both oceans — a cell can belong to both sets.
- Seeding only the corners instead of full border rows/columns — misses many reachable cells.
Practice
Try the solution yourself
Edit the optimal implementation, test another input, and observe the result.
Editable code previewpublic List<List<Integer>> pacificAtlantic(int[][] heights) { int m = heights.length, n = heights[0].length; boolean[][] pacific = new boolean[m][n]; boolean[][] atlantic = new boolean[m][n]; for (int r = 0; r < m; r++) {Explore the playgroundClose the playground
Avoid mistakes
Recognize the interview traps
Understand why common attempts fail before reviewing the corrected implementation.
1Wrong comparison operator (> vs >=)
Forward flow is allowed when neighbour ≤ current (equal allowed). In the reversed climb you must move to neighbours ≥ current, so the operator is >=; using > blocks valid equal-height paths.
Explore the code comparisonHide the code comparison
Wrong comparison operator (> vs >=)
Forward flow is allowed when neighbour ≤ current (equal allowed). In the reversed climb you must move to neighbours ≥ current, so the operator is >=; using > blocks valid equal-height paths.
Don't write this
if heights[nr][nc] > heights[r][c]: # blocks equal heights
dfs(nr, nc, ocean)Write this instead
if heights[nr][nc] >= heights[r][c]: # equal heights pass
dfs(nr, nc, ocean)2Shared visited set for both oceans
A cell can drain to both oceans, so it must be markable in both sets. One shared visited matrix would block the second ocean's traversal from re-marking it.
Explore the code comparisonHide the code comparison
Shared visited set for both oceans
A cell can drain to both oceans, so it must be markable in both sets. One shared visited matrix would block the second ocean's traversal from re-marking it.
Don't write this
boolean[][] visited = new boolean[m][n]; // shared
dfs(h, r, 0, visited); // pacific
dfs(h, r, n-1, visited); // atlantic blocked by pacific marksWrite this instead
boolean[][] pacific = new boolean[m][n];
boolean[][] atlantic = new boolean[m][n];
dfs(h, r, 0, pacific);
dfs(h, r, n-1, atlantic);Revise
Carry the pattern into the interview
Pattern to remember
Reverse multi-source DFS/BFS from both borders, then intersect
Code pattern to memorize
pacific = cells reachable climbing from top+left borders
atlantic = cells reachable climbing from bottom+right borders
answer = [(r,c) for all cells if (r,c) in pacific and in atlantic]
# reverse rule: move to neighbour iff height[nb] >= height[cur]Rules to remember
- 1Reverse the flow: water flows downhill, so to find what reaches an ocean, climb UPHILL from the ocean inward (
neighbour ≥ current). - 2Run two traversals: one seeded from Pacific borders (top row + left col), one from Atlantic borders (bottom row + right col).
- 3Use a visited set per ocean; the answer is the intersection of the two sets.
- 4Multi-source: seed the traversal with ALL border cells of that ocean at once, not one DFS per cell.
- 5The comparison is
>=(not>) — equal-height neighbours still let water pass.
Use this pattern when
- 'Which cells can reach multiple targets/borders' on a grid
- Reachability where simulating from each source is too expensive — reverse from the targets
- Problems answered by intersecting two reachability sets
- Border-seeded multi-source flood fill
Choose another pattern when
- Single source/target → one ordinary BFS/DFS
- Shortest distance needed → BFS with distance, not just reachability
- Weighted heights with costs → Dijkstra, not flat flood fill
Interview takeaway
Pacific Atlantic teaches the 'reverse the search from the goal' trick: instead of asking 'can this cell reach an ocean?' n times, ask 'which cells can the ocean reach?' twice and intersect. The same reverse-multi-source idea solves Surrounded Regions and Walls and Gates.
Continue
Transfer the pattern to another problem
Use a direct variation or pattern sibling to prove the idea is reusable.
Transferable patternReverse multi-source flood fill from the targets, then intersect reachable sets. The key insight is searching backward from few targets instead of forward from many sources. Same family as Surrounded Regions and Walls and Gates.
Practice queueDirect variations and pattern siblings
Direct follow-ups
- Surrounded RegionsReverse from the borders again: mark border-connected regions safe, flip the rest.
- Number of IslandsSame grid flood-fill skeleton; count components instead of reverse-reachability.
- Walls and GatesComing soonMulti-source BFS from all gates at once — the distance version of multi-source seeding.
- Rotting OrangesMulti-source BFS counting minutes from all rotten oranges simultaneously.