medium tree, graph, dp questions
This commit is contained in:
157
backend/data/questions/number-of-islands.yaml
Normal file
157
backend/data/questions/number-of-islands.yaml
Normal file
@@ -0,0 +1,157 @@
|
||||
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.
|
||||
Reference in New Issue
Block a user