🧠
Brute Force (DFS with Visited Set)
💡 Starting with brute force DFS helps understand the problem as exploring each cell and marking connected lands. It is intuitive and lays the foundation for optimized approaches.
Intuition
Traverse every cell; when land is found, perform DFS to mark all connected land cells as visited, then increment island count.
Algorithm
- Initialize island count to zero.
- Iterate over each cell in the grid.
- If the cell is land and not visited, perform DFS to mark all connected land cells.
- Increment island count after each DFS call.
💡 The main challenge is to correctly mark visited cells to avoid recounting and to explore all four directions safely.
from typing import List
def numIslands(grid: List[List[str]]) -> int:
if not grid:
return 0
rows, cols = len(grid), len(grid[0])
visited = set()
def dfs(r, c):
if (r < 0 or c < 0 or r >= rows or c >= cols or
grid[r][c] == '0' or (r, c) in visited):
return
visited.add((r, c))
dfs(r+1, c)
dfs(r-1, c)
dfs(r, c+1)
dfs(r, c-1)
count = 0
for r in range(rows):
for c in range(cols):
if grid[r][c] == '1' and (r, c) not in visited:
dfs(r, c)
count += 1
return count
# Driver code
if __name__ == '__main__':
grid = [
["1","1","0","0","0"],
["1","1","0","0","0"],
["0","0","1","0","0"],
["0","0","0","1","1"]
]
print(numIslands(grid)) # Expected output: 3
Line Notes
if not grid:Check for empty input to avoid errors.
visited = set()Track visited cells to prevent revisiting and infinite recursion.
def dfs(r, c):Define recursive DFS to explore connected land.
if (r < 0 or c < 0 or r >= rows or c >= cols or grid[r][c] == '0' or (r, c) in visited):Base case to stop recursion on water, out-of-bounds, or visited cells.
visited.add((r, c))Mark current cell as visited to avoid reprocessing.
dfs(r+1, c)Explore downward neighbor.
dfs(r-1, c)Explore upward neighbor.
dfs(r, c+1)Explore right neighbor.
dfs(r, c-1)Explore left neighbor.
for r in range(rows):Iterate over each row in the grid.
for c in range(cols):Iterate over each column in the grid.
if grid[r][c] == '1' and (r, c) not in visited:Start DFS only on unvisited land cells.
count += 1Increment island count after fully exploring one island.
import java.util.*;
public class NumberOfIslands {
public int numIslands(char[][] grid) {
if (grid == null || grid.length == 0) return 0;
int rows = grid.length, cols = grid[0].length;
boolean[][] visited = new boolean[rows][cols];
int count = 0;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (grid[r][c] == '1' && !visited[r][c]) {
dfs(grid, visited, r, c);
count++;
}
}
}
return count;
}
private void dfs(char[][] grid, boolean[][] visited, int r, int c) {
if (r < 0 || c < 0 || r >= grid.length || c >= grid[0].length ||
grid[r][c] == '0' || visited[r][c]) return;
visited[r][c] = true;
dfs(grid, visited, r + 1, c);
dfs(grid, visited, r - 1, c);
dfs(grid, visited, r, c + 1);
dfs(grid, visited, r, c - 1);
}
public static void main(String[] args) {
NumberOfIslands solver = new NumberOfIslands();
char[][] grid = {
{'1','1','0','0','0'},
{'1','1','0','0','0'},
{'0','0','1','0','0'},
{'0','0','0','1','1'}
};
System.out.println(solver.numIslands(grid)); // Expected output: 3
}
}
Line Notes
if (grid == null || grid.length == 0) return 0;Handle empty or null input gracefully.
boolean[][] visited = new boolean[rows][cols];Track visited cells to avoid revisiting.
if (grid[r][c] == '1' && !visited[r][c]) {Start DFS only on unvisited land cells.
visited[r][c] = true;Mark current cell as visited to prevent cycles.
dfs(grid, visited, r + 1, c);Explore downward neighbor recursively.
dfs(grid, visited, r - 1, c);Explore upward neighbor recursively.
dfs(grid, visited, r, c + 1);Explore right neighbor recursively.
dfs(grid, visited, r, c - 1);Explore left neighbor recursively.
for (int r = 0; r < rows; r++) {Iterate over each row in the grid.
for (int c = 0; c < cols; c++) {Iterate over each column in the grid.
count++;Increment island count after DFS completes for one island.
#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:
void dfs(vector<vector<char>>& grid, vector<vector<bool>>& visited, int r, int c) {
int rows = grid.size();
int cols = grid[0].size();
if (r < 0 || c < 0 || r >= rows || c >= cols ||
grid[r][c] == '0' || visited[r][c]) return;
visited[r][c] = true;
dfs(grid, visited, r + 1, c);
dfs(grid, visited, r - 1, c);
dfs(grid, visited, r, c + 1);
dfs(grid, visited, r, c - 1);
}
int numIslands(vector<vector<char>>& grid) {
if (grid.empty()) return 0;
int rows = grid.size();
int cols = grid[0].size();
vector<vector<bool>> visited(rows, vector<bool>(cols, false));
int count = 0;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
if (grid[r][c] == '1' && !visited[r][c]) {
dfs(grid, visited, r, c);
count++;
}
}
}
return count;
}
};
int main() {
Solution sol;
vector<vector<char>> grid = {
{'1','1','0','0','0'},
{'1','1','0','0','0'},
{'0','0','1','0','0'},
{'0','0','0','1','1'}
};
cout << sol.numIslands(grid) << endl; // Expected output: 3
return 0;
}
Line Notes
if (grid.empty()) return 0;Check for empty grid to avoid errors.
vector<vector<bool>> visited(rows, vector<bool>(cols, false));Initialize visited matrix to track explored cells.
if (grid[r][c] == '1' && !visited[r][c]) {Start DFS only on unvisited land cells.
visited[r][c] = true;Mark current cell visited to prevent revisiting.
dfs(grid, visited, r + 1, c);Explore downward neighbor recursively.
dfs(grid, visited, r - 1, c);Explore upward neighbor recursively.
dfs(grid, visited, r, c + 1);Explore right neighbor recursively.
dfs(grid, visited, r, c - 1);Explore left neighbor recursively.
for (int r = 0; r < rows; r++) {Iterate over all rows.
for (int c = 0; c < cols; c++) {Iterate over all columns.
count++;Increment island count after DFS completes.
var numIslands = function(grid) {
if (!grid || grid.length === 0) return 0;
const rows = grid.length, cols = grid[0].length;
const visited = new Set();
function dfs(r, c) {
if (r < 0 || c < 0 || r >= rows || c >= cols ||
grid[r][c] === '0' || visited.has(r + ',' + c)) return;
visited.add(r + ',' + c);
dfs(r + 1, c);
dfs(r - 1, c);
dfs(r, c + 1);
dfs(r, c - 1);
}
let count = 0;
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
if (grid[r][c] === '1' && !visited.has(r + ',' + c)) {
dfs(r, c);
count++;
}
}
}
return count;
};
// Test
const grid = [
['1','1','0','0','0'],
['1','1','0','0','0'],
['0','0','1','0','0'],
['0','0','0','1','1']
];
console.log(numIslands(grid)); // Expected output: 3
Line Notes
if (!grid || grid.length === 0) return 0;Guard clause for empty input.
const visited = new Set();Use a set to track visited cells uniquely.
if (r < 0 || c < 0 || r >= rows || c >= cols || grid[r][c] === '0' || visited.has(r + ',' + c)) return;Stop DFS on invalid or visited cells.
visited.add(r + ',' + c);Mark current cell visited to avoid cycles.
dfs(r + 1, c);Explore downward neighbor.
dfs(r - 1, c);Explore upward neighbor.
dfs(r, c + 1);Explore right neighbor.
dfs(r, c - 1);Explore left neighbor.
for (let r = 0; r < rows; r++) {Iterate over rows.
for (let c = 0; c < cols; c++) {Iterate over columns.
count++;Increment island count after DFS completes.
We visit each cell once, and DFS explores connected lands marking them visited. The visited set or matrix can grow up to m*n in worst case.
💡 For a 300x300 grid, this means up to 90,000 operations, which is efficient enough for interview constraints.
Interview Verdict: Accepted
This approach is accepted and efficient enough for typical interview constraints, making it a solid baseline solution.