Number of Islands BFS and DFS in DSA Python - Time & Space Complexity
We want to understand how the time needed to find islands grows as the map size grows.
How does the number of steps change when the grid gets bigger?
Analyze the time complexity of the following code snippet.
def num_islands(grid):
if not grid:
return 0
count = 0
rows, cols = len(grid), len(grid[0])
def dfs(r, c):
if r < 0 or c < 0 or r >= rows or c >= cols or 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 r in range(rows):
for c in range(cols):
if grid[r][c] == '1':
dfs(r, c)
count += 1
return count
This code counts islands by visiting each land cell and marking connected land cells as visited using DFS.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Visiting each cell once during DFS or the main loops.
- How many times: Each cell is checked once in the nested loops and visited once in DFS.
As the grid size grows, the number of cells to check grows too.
| Input Size (n = rows * cols) | Approx. Operations |
|---|---|
| 10 | About 10 visits |
| 100 | About 100 visits |
| 1000 | About 1000 visits |
Pattern observation: The steps grow roughly in direct proportion to the number of cells.
Time Complexity: O(rows * cols)
This means the time grows linearly with the total number of cells in the grid.
[X] Wrong: "DFS repeats work many times, so time is more than linear."
[OK] Correct: Each cell is visited once and marked visited, so no cell is counted multiple times.
Understanding this helps you explain how to efficiently explore connected parts in grids, a common interview skill.
"What if we used a queue and BFS instead of recursion for traversal? How would the time complexity change?"
Practice
Solution
Step 1: Understand the grid representation
The grid contains '1's representing land and '0's representing water.Step 2: Identify what the problem asks
It asks to count how many separate groups of connected '1's (islands) are present.Final Answer:
Count how many groups of connected '1's (islands) exist -> Option CQuick Check:
Number of islands = count of connected '1' groups [OK]
- Confusing island count with island size
- Counting '0's instead of '1's
- Calculating perimeter instead of count
Solution
Step 1: Check boundary and water conditions
def dfs(i, j): if i<0 or j<0 or i>=len(grid) or j>=len(grid[0]) or grid[i][j] == '0': return; grid[i][j] = '0'; dfs(i+1,j); dfs(i-1,j); dfs(i,j+1); dfs(i,j-1) correctly checks if indices are out of bounds or cell is water ('0') and returns.Step 2: Mark current land as visited and recurse
def dfs(i, j): if i<0 or j<0 or i>=len(grid) or j>=len(grid[0]) or grid[i][j] == '0': return; grid[i][j] = '0'; dfs(i+1,j); dfs(i-1,j); dfs(i,j+1); dfs(i,j-1) marks grid[i][j] = '0' to avoid revisiting and calls dfs on all four neighbors.Final Answer:
Option A code correctly implements DFS with boundary checks and marking visited -> Option AQuick Check:
DFS with boundary and visited marking = def dfs(i, j): if i<0 or j<0 or i>=len(grid) or j>=len(grid[0]) or grid[i][j] == '0': return; grid[i][j] = '0'; dfs(i+1,j); dfs(i-1,j); dfs(i,j+1); dfs(i,j-1) [OK]
- Not checking boundaries before recursion
- Not marking visited cells
- Using loops incorrectly inside DFS
grid = [
['1','1','0','0'],
['1','0','0','1'],
['0','0','1','1'],
['0','0','0','0']
]
count = 0
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == '1':
count += 1
stack = [(i,j)]
while stack:
x,y = stack.pop()
if 0 <= x < len(grid) and 0 <= y < len(grid[0]) and grid[x][y] == '1':
grid[x][y] = '0'
stack.extend([(x+1,y),(x-1,y),(x,y+1),(x,y-1)])
print(count)Solution
Step 1: Identify islands in the grid
The grid has three islands: top-left (cells (0,0),(0,1),(1,0)), single cell island at (1,3), and bottom-right island (cells (2,2),(2,3)).Step 2: Trace the DFS using stack
Each '1' found triggers DFS marking connected '1's as '0'. The count increments for each new island found. Total islands counted = 3.Final Answer:
3 -> Option BQuick Check:
Number of islands found by DFS = 3 [OK]
- Counting each '1' without marking visited
- Misidentifying connected cells
- Off-by-one errors in loops
def dfs(i, j):
if i < 0 or j < 0 or i >= len(grid) or j >= len(grid[0]):
return
if grid[i][j] == '0':
return
dfs(i+1, j)
dfs(i-1, j)
dfs(i, j+1)
dfs(i, j-1)
count = 0
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == '1':
count += 1
dfs(i, j)
print(count)Solution
Step 1: Analyze DFS function behavior
The DFS checks boundaries and water but never marks visited land cells as '0' or visited.Step 2: Identify consequence of missing visited marking
Without marking visited, DFS revisits same cells repeatedly, causing infinite recursion or stack overflow.Final Answer:
The code does not mark visited cells, causing infinite recursion -> Option DQuick Check:
Missing visited marking causes infinite recursion [OK]
- Forgetting to mark visited cells
- Incorrect boundary conditions
- Incrementing count inside DFS
Solution
Step 1: Understand diagonal connectivity
Diagonal connections mean neighbors include cells diagonally adjacent, not just up/down/left/right.Step 2: Modify search directions
Add diagonal neighbors (i+1,j+1), (i+1,j-1), (i-1,j+1), (i-1,j-1) to BFS or DFS neighbor checks to include diagonals.Final Answer:
Add diagonal neighbors (i+1,j+1), (i+1,j-1), (i-1,j+1), (i-1,j-1) to the search directions -> Option AQuick Check:
Include diagonals in neighbors for diagonal connectivity [OK]
- Ignoring diagonal neighbors
- Not marking visited cells
- Counting without traversal
Ready to prove it?
Pass the test and this pattern moves unknown
