158 lines
4.8 KiB
YAML
158 lines
4.8 KiB
YAML
title: Number of Islands
|
||
slug: number-of-islands
|
||
difficulty: medium
|
||
leetcode_id: 200
|
||
leetcode_url: https://leetcode.com/problems/number-of-islands/
|
||
categories:
|
||
- graphs
|
||
- arrays
|
||
patterns:
|
||
- dfs
|
||
- bfs
|
||
|
||
description: |
|
||
Given an m x n 2D binary grid `grid` which represents a map of '1's (land) and '0's (water),
|
||
return the number of islands.
|
||
|
||
An island is surrounded by water and is formed by connecting adjacent lands horizontally
|
||
or vertically. You may assume all four edges of the grid are surrounded by water.
|
||
|
||
constraints: |
|
||
- m == grid.length
|
||
- n == grid[i].length
|
||
- 1 <= m, n <= 300
|
||
- grid[i][j] is '0' or '1'
|
||
|
||
examples:
|
||
- input: |
|
||
grid = [
|
||
["1","1","1","1","0"],
|
||
["1","1","0","1","0"],
|
||
["1","1","0","0","0"],
|
||
["0","0","0","0","0"]
|
||
]
|
||
output: "1"
|
||
explanation: "All land cells are connected, forming one island."
|
||
- input: |
|
||
grid = [
|
||
["1","1","0","0","0"],
|
||
["1","1","0","0","0"],
|
||
["0","0","1","0","0"],
|
||
["0","0","0","1","1"]
|
||
]
|
||
output: "3"
|
||
explanation: "Three separate connected components of land."
|
||
|
||
explanation:
|
||
approach: |
|
||
1. Iterate through every cell in the grid
|
||
2. When a '1' (land) is found, increment island count
|
||
3. Use DFS/BFS to mark all connected land cells as visited
|
||
4. Continue iteration until all cells are processed
|
||
|
||
intuition: |
|
||
Each island is a connected component of '1's. We need to count these components.
|
||
|
||
When we find an unvisited '1', we've discovered a new island. We then "sink" the entire
|
||
island by marking all connected '1's as visited (either change to '0' or use a visited set).
|
||
This ensures we don't count the same island multiple times.
|
||
|
||
common_pitfalls:
|
||
- title: Not marking visited cells
|
||
description: |
|
||
Without marking cells as visited, you'll count the same island multiple times
|
||
or get infinite loops in DFS/BFS.
|
||
wrong_approach: "Not modifying grid or using visited set"
|
||
correct_approach: "Mark cell as '0' or add to visited set when processing"
|
||
|
||
- title: Diagonal connections
|
||
description: |
|
||
Islands only connect horizontally and vertically, not diagonally.
|
||
Only explore 4 directions, not 8.
|
||
|
||
- title: Boundary checks
|
||
description: |
|
||
Always check if row/col are within bounds before accessing grid.
|
||
|
||
key_takeaways:
|
||
- Grid problems often reduce to graph traversal
|
||
- DFS or BFS both work for exploring connected components
|
||
- Modifying input can serve as "visited" tracking
|
||
- This pattern applies to many "count components" problems
|
||
|
||
time_complexity: "O(m × n)"
|
||
space_complexity: "O(m × n)"
|
||
complexity_explanation: |
|
||
Time: Each cell is visited at most once.
|
||
Space: DFS recursion stack or BFS queue can hold O(m × n) cells in worst case.
|
||
|
||
solutions:
|
||
- approach_name: DFS (Optimal)
|
||
is_optimal: true
|
||
code: |
|
||
def num_islands(grid: list[list[str]]) -> int:
|
||
if not grid:
|
||
return 0
|
||
|
||
rows, cols = len(grid), len(grid[0])
|
||
islands = 0
|
||
|
||
def dfs(r: int, c: int) -> None:
|
||
if r < 0 or r >= rows or c < 0 or c >= cols:
|
||
return
|
||
if grid[r][c] != '1':
|
||
return
|
||
|
||
grid[r][c] = '0' # Mark as visited
|
||
|
||
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':
|
||
islands += 1
|
||
dfs(r, c)
|
||
|
||
return islands
|
||
explanation: |
|
||
When land is found, increment count and sink the entire island using DFS.
|
||
Modifying the grid serves as our visited marker.
|
||
|
||
- approach_name: BFS
|
||
is_optimal: true
|
||
code: |
|
||
from collections import deque
|
||
|
||
def num_islands(grid: list[list[str]]) -> int:
|
||
if not grid:
|
||
return 0
|
||
|
||
rows, cols = len(grid), len(grid[0])
|
||
islands = 0
|
||
|
||
def bfs(start_r: int, start_c: int) -> None:
|
||
queue = deque([(start_r, start_c)])
|
||
grid[start_r][start_c] = '0'
|
||
|
||
while queue:
|
||
r, c = queue.popleft()
|
||
for dr, dc in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
|
||
nr, nc = r + dr, c + dc
|
||
if 0 <= nr < rows and 0 <= nc < cols and grid[nr][nc] == '1':
|
||
grid[nr][nc] = '0'
|
||
queue.append((nr, nc))
|
||
|
||
for r in range(rows):
|
||
for c in range(cols):
|
||
if grid[r][c] == '1':
|
||
islands += 1
|
||
bfs(r, c)
|
||
|
||
return islands
|
||
explanation: |
|
||
Same logic using BFS instead of DFS.
|
||
Avoids recursion stack but uses queue space.
|