🧠
Brute Force (DFS from every cell)
💡 This approach tries to simulate the water flow from each cell independently to check if it can reach both oceans. It is straightforward but inefficient, helping beginners understand the problem deeply before optimizing.
Intuition
For each cell, perform two DFS traversals to see if water can reach the Pacific and Atlantic oceans by moving only to neighbors with height less or equal to current cell.
Algorithm
- For each cell in the matrix:
- Run DFS to check if it can reach the Pacific ocean by moving only to neighbors with height <= current cell.
- Run DFS to check if it can reach the Atlantic ocean similarly.
- If both DFS return true, add the cell to the result.
💡 The challenge is to understand how to simulate water flow and how to check reachability to oceans from each cell separately.
from typing import List
class Solution:
def pacificAtlantic(self, heights: List[List[int]]) -> List[List[int]]:
if not heights or not heights[0]:
return []
m, n = len(heights), len(heights[0])
def dfs(r, c, visited, ocean_check):
# If cell is on the ocean border, it can reach that ocean
if ocean_check(r, c):
return True
visited.add((r, c))
for dr, dc in [(1,0),(-1,0),(0,1),(0,-1)]:
nr, nc = r + dr, c + dc
if 0 <= nr < m and 0 <= nc < n and (nr, nc) not in visited and heights[nr][nc] <= heights[r][c]:
if dfs(nr, nc, visited, ocean_check):
return True
return False
result = []
for i in range(m):
for j in range(n):
if dfs(i, j, set(), lambda r, c: r == 0 or c == 0) and dfs(i, j, set(), lambda r, c: r == m - 1 or c == n - 1):
result.append([i, j])
return result
# Driver code
if __name__ == '__main__':
sol = Solution()
matrix = [[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]]
print(sol.pacificAtlantic(matrix))
Line Notes
if not heights or not heights[0]:Check for empty input to avoid errors
def dfs(r, c, visited, ocean_check):Define DFS to explore if cell can reach the ocean defined by ocean_check
if ocean_check(r, c):If current cell is on ocean border, it can reach that ocean
if 0 <= nr < m and 0 <= nc < n and (nr, nc) not in visited and heights[nr][nc] <= heights[r][c]:Move only to neighbors with height less or equal and not visited
import java.util.*;
public class Solution {
private int m, n;
private int[][] heights;
public List<List<Integer>> pacificAtlantic(int[][] heights) {
this.heights = heights;
m = heights.length;
n = heights[0].length;
List<List<Integer>> result = new ArrayList<>();
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (dfs(i, j, new HashSet<>(), (r, c) -> r == 0 || c == 0) && dfs(i, j, new HashSet<>(), (r, c) -> r == m - 1 || c == n - 1)) {
result.add(Arrays.asList(i, j));
}
}
}
return result;
}
private boolean dfs(int r, int c, Set<String> visited, OceanCheck oceanCheck) {
String key = r + "," + c;
if (oceanCheck.isOcean(r, c)) return true;
visited.add(key);
int[][] directions = {{1,0},{-1,0},{0,1},{0,-1}};
for (int[] d : directions) {
int nr = r + d[0], nc = c + d[1];
String nKey = nr + "," + nc;
if (nr >= 0 && nr < m && nc >= 0 && nc < n && !visited.contains(nKey) && heights[nr][nc] <= heights[r][c]) {
if (dfs(nr, nc, visited, oceanCheck)) return true;
}
}
return false;
}
interface OceanCheck {
boolean isOcean(int r, int c);
}
// Driver code
public static void main(String[] args) {
Solution sol = new Solution();
int[][] matrix = {
{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}
};
System.out.println(sol.pacificAtlantic(matrix));
}
}
Line Notes
if (oceanCheck.isOcean(r, c)) return true;If current cell is on ocean border, it can reach that ocean
visited.add(key);Mark current cell as visited to avoid cycles
if (nr >= 0 && nr < m && nc >= 0 && nc < n && !visited.contains(nKey) && heights[nr][nc] <= heights[r][c])Move only to neighbors with height less or equal and not visited
return false;Return false if no path to ocean found from this cell
#include <iostream>
#include <vector>
#include <set>
#include <functional>
using namespace std;
class Solution {
int m, n;
vector<vector<int>> heights;
public:
vector<vector<int>> pacificAtlantic(vector<vector<int>>& heights) {
this->heights = heights;
m = heights.size();
n = heights[0].size();
vector<vector<int>> result;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
set<pair<int,int>> visited1, visited2;
if (dfs(i, j, visited1, [](int r, int c, int m, int n){ return r == 0 || c == 0; }) &&
dfs(i, j, visited2, [](int r, int c, int m, int n){ return r == m - 1 || c == n - 1; })) {
result.push_back({i, j});
}
}
}
return result;
}
bool dfs(int r, int c, set<pair<int,int>>& visited, function<bool(int,int,int,int)> oceanCheck) {
if (oceanCheck(r, c, m, n)) return true;
visited.insert({r, c});
int directions[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
for (auto& d : directions) {
int nr = r + d[0], nc = c + d[1];
if (nr >= 0 && nr < m && nc >= 0 && nc < n && visited.count({nr, nc}) == 0 && heights[nr][nc] <= heights[r][c]) {
if (dfs(nr, nc, visited, oceanCheck)) return true;
}
}
return false;
}
};
int main() {
Solution sol;
vector<vector<int>> matrix = {
{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}
};
vector<vector<int>> res = sol.pacificAtlantic(matrix);
for (auto& cell : res) {
cout << "[" << cell[0] << "," << cell[1] << "] ";
}
cout << endl;
return 0;
}
Line Notes
if (oceanCheck(r, c, m, n)) return true;If current cell is on ocean border, it can reach that ocean
visited.insert({r, c});Mark current cell as visited to avoid cycles
if (nr >= 0 && nr < m && nc >= 0 && nc < n && visited.count({nr, nc}) == 0 && heights[nr][nc] <= heights[r][c])Move only to neighbors with height less or equal and not visited
return false;Return false if no path to ocean found from this cell
var pacificAtlantic = function(heights) {
if (!heights || heights.length === 0) return [];
const m = heights.length, n = heights[0].length;
function dfs(r, c, visited, oceanCheck) {
if (oceanCheck(r, c)) return true;
const key = r + ',' + c;
visited.add(key);
const directions = [[1,0],[-1,0],[0,1],[0,-1]];
for (const [dr, dc] of directions) {
const nr = r + dr, nc = c + dc;
const nKey = nr + ',' + nc;
if (nr >= 0 && nr < m && nc >= 0 && nc < n && !visited.has(nKey) && heights[nr][nc] <= heights[r][c]) {
if (dfs(nr, nc, visited, oceanCheck)) return true;
}
}
return false;
}
const result = [];
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (dfs(i, j, new Set(), (r, c) => r === 0 || c === 0) && dfs(i, j, new Set(), (r, c) => r === m - 1 || c === n - 1)) {
result.push([i, j]);
}
}
}
return result;
};
// Driver code
const matrix = [[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]];
console.log(pacificAtlantic(matrix));
Line Notes
if (!heights || heights.length === 0) return [];Handle empty input gracefully
if (oceanCheck(r, c)) return true;If current cell is on ocean border, it can reach that ocean
visited.add(key);Mark current cell as visited to avoid cycles
if (nr >= 0 && nr < m && nc >= 0 && nc < n && !visited.has(nKey) && heights[nr][nc] <= heights[r][c])Move only to neighbors with height less or equal and not visited
TimeO(m^2 * n^2)
SpaceO(m * n)
For each cell, DFS explores up to O(m*n) cells, leading to O(m^2 * n^2) in total.
💡 For a 100x100 grid, this means 10,000 cells each doing DFS over 10,000 cells, totaling 100 million operations, which is too slow.
Interview Verdict: TLE
This approach is too slow for large inputs but helps understand the problem and DFS traversal.