Number of Islands BFS and DFS in DSA Javascript - Time & Space Complexity
We want to understand how the time needed to find islands grows as the grid size increases.
How does the number of cells affect the work done by BFS or DFS?
Analyze the time complexity of the following code snippet.
function numIslands(grid) {
let count = 0;
const rows = grid.length;
const cols = grid[0].length;
function dfs(r, c) {
if (r < 0 || c < 0 || r >= rows || c >= cols || grid[r][c] === '0') return;
grid[r][c] = '0';
dfs(r + 1, c);
dfs(r - 1, c);
dfs(r, c + 1);
dfs(r, c - 1);
}
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
if (grid[r][c] === '1') {
count++;
dfs(r, c);
}
}
}
return count;
}
This code counts islands by running DFS to mark connected land cells as visited.
- Primary operation: DFS visits each cell connected to land once.
- How many times: Each cell is visited at most once during DFS or the outer loops.
As the grid size grows, the total number of cells increases, and each cell is checked once.
| Input Size (n = rows * cols) | Approx. Operations |
|---|---|
| 10 | About 10 checks and visits |
| 100 | About 100 checks and visits |
| 1000 | About 1000 checks and visits |
Pattern observation: The work grows roughly in direct proportion to the number of cells.
Time Complexity: O(rows * cols)
This means the time needed grows linearly with the total number of cells in the grid.
[X] Wrong: "DFS runs multiple times on the same cells, so time is more than linear."
[OK] Correct: Each cell is marked visited (turned to '0') after first visit, so DFS never revisits it, keeping time linear.
Understanding this helps you explain how graph traversal algorithms like DFS and BFS efficiently explore connected areas in grids.
"What if the grid was very sparse with few islands? How would the time complexity change in practice?"
Practice
Solution
Step 1: Understand the grid representation
The grid contains '1's representing land and '0's representing water.Step 2: Identify what an island means
An island is a group of connected '1's horizontally or vertically.Final Answer:
Count how many groups of connected '1's (islands) are in the grid -> Option AQuick Check:
Number of islands = count of connected '1' groups [OK]
- Confusing island count with largest island size
- Counting '0's instead of '1's
- Ignoring connectivity rules (only horizontal/vertical)
Solution
Step 1: Check boundary conditions for DFS
We must stop DFS if row or column is outside grid bounds.Step 2: Write correct boundary check
Row or column less than 0 or greater or equal to grid size means out of bounds.Final Answer:
function dfs(grid, r, c) { if (r < 0 || c < 0 || r >= grid.length || c >= grid[0].length) return; } -> Option DQuick Check:
Boundary check includes all invalid indices [OK]
- Using > instead of >= for boundary check
- Missing some boundary conditions
- Using <= 0 which excludes valid index 0
const grid = [
['1','1','0','0'],
['1','0','0','1'],
['0','0','1','1'],
['0','0','0','0']
];
function numIslands(grid) {
let count = 0;
const dfs = (r, c) => {
if (r < 0 || c < 0 || r >= grid.length || c >= grid[0].length || grid[r][c] === '0') return;
grid[r][c] = '0';
dfs(r + 1, c);
dfs(r - 1, c);
dfs(r, c + 1);
dfs(r, c - 1);
};
for (let r = 0; r < grid.length; r++) {
for (let c = 0; c < grid[0].length; c++) {
if (grid[r][c] === '1') {
dfs(r, c);
count++;
}
}
}
return count;
}
console.log(numIslands(grid));Solution
Step 1: Identify islands in the grid
Islands are groups of connected '1's. Here, islands are: top-left (3 cells: (0,0),(0,1),(1,0)), single cell at (1,3), and bottom cluster (2 cells: (2,2),(2,3)). Total islands = 3.Step 2: Count islands using DFS
DFS marks visited '1's as '0'. After visiting each island, count increments. Total islands counted = 3.Final Answer:
3 -> Option BQuick Check:
Count connected '1' groups = 3 [OK]
- Counting diagonal connections as islands
- Not marking visited cells, causing overcount
- Misreading grid layout
function bfs(grid, r, c) {
const queue = [[r, c]];
while (queue.length > 0) {
const [row, col] = queue.shift();
if (row < 0 || col < 0 || row >= grid.length || col >= grid[0].length || grid[row][col] === '0') continue;
grid[row][col] = '0';
queue.push([row + 1, col]);
queue.push([row - 1, col]);
queue.push([row, col + 1]);
queue.push([row, col - 1]);
}
}Solution
Step 1: Analyze neighbor addition in BFS
The code adds neighbors to the queue without checking if they are visited or water.Step 2: Identify consequence of missing check
This causes multiple visits to the same cell, increasing runtime and possible infinite loops.Final Answer:
It does not check if a cell is already visited before pushing neighbors -> Option AQuick Check:
Check before enqueueing neighbors to avoid repeats [OK]
- Thinking queue.shift() inefficiency is the bug here
- Marking visited after enqueue instead of before
- Confusing recursion with iteration
Solution
Step 1: Understand connectivity rules
Diagonal connections mean neighbors include diagonals, not just up/down/left/right.Step 2: Modify DFS to include diagonal neighbors
Add DFS calls for (r+1,c+1), (r+1,c-1), (r-1,c+1), (r-1,c-1) along with existing neighbors.Final Answer:
Add diagonal neighbors (r+1,c+1), (r+1,c-1), (r-1,c+1), (r-1,c-1) to DFS calls -> Option CQuick Check:
Include diagonal neighbors for diagonal connectivity [OK]
- Ignoring diagonal neighbors when required
- Switching BFS/DFS without changing neighbor logic
- Counting only horizontal or vertical neighbors
Ready to prove it?
Pass the test and this pattern moves unknown
