mirror of
https://github.com/prdlk/leetcode.git
synced 2026-11-02 21:22:43 +00:00
111 lines
2.8 KiB
Plaintext
111 lines
2.8 KiB
Plaintext
---
|
|
title: Depth-First Search
|
|
---
|
|
|
|
# Depth-First Search (DFS)
|
|
|
|
## The idea
|
|
|
|
BFS searches in rings. DFS picks one path and follows it to the end.
|
|
Dead end? Back up one step. Try the next branch.
|
|
|
|
Like exploring a maze with one hand on the wall.
|
|
|
|
Use DFS when:
|
|
- The answer **composes from subtrees** (depth, path sums, subtree checks).
|
|
- You need **all** of a region (islands, flood fill, connected components).
|
|
|
|
Use BFS when you need **shortest path**. DFS does not give shortest path.
|
|
|
|
## The picture
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
A((1)) --> B((2))
|
|
A --> C((5))
|
|
B --> D((3))
|
|
B --> E((4))
|
|
C --> F((6))
|
|
|
|
style A fill:#1565c0,color:#fff
|
|
style B fill:#1565c0,color:#fff
|
|
style D fill:#1565c0,color:#fff
|
|
```
|
|
|
|
Visit order: 1 → 2 → 3 (bottom!) → back up → 4 → back up → 5 → 6.
|
|
Numbers show the order. DFS goes **deep before wide**.
|
|
|
|
## Tree DFS — answers flow up (LC 104 — Max Depth)
|
|
|
|
The pattern: ask each child a question. Combine the answers. Return up.
|
|
|
|
```python
|
|
def max_depth(root) -> int:
|
|
if root is None:
|
|
return 0 # base case
|
|
left = max_depth(root.left)
|
|
right = max_depth(root.right)
|
|
return 1 + max(left, right) # combine + return up
|
|
```
|
|
|
|
```mermaid
|
|
flowchart BT
|
|
D["leaf returns 1"] --> B["returns 1 + max(1,1) = 2"]
|
|
E["leaf returns 1"] --> B
|
|
B --> A["root returns 1 + max(2,1) = 3"]
|
|
C["leaf returns 1"] --> A
|
|
|
|
style A fill:#2e7d32,color:#fff
|
|
```
|
|
|
|
## Graph DFS — add a visited set (LC 200 — Number of Islands)
|
|
|
|
Graphs have cycles. Trees do not.
|
|
So graph DFS needs one new thing: **mark where you have been.**
|
|
On a grid, sink the land as you visit it — the grid *is* the visited set.
|
|
|
|
```python
|
|
def num_islands(grid: list[list[str]]) -> int:
|
|
rows, cols = len(grid), len(grid[0])
|
|
count = 0
|
|
|
|
def sink(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 visited
|
|
sink(r + 1, c)
|
|
sink(r - 1, c)
|
|
sink(r, c + 1)
|
|
sink(r, c - 1)
|
|
|
|
for r in range(rows):
|
|
for c in range(cols):
|
|
if grid[r][c] == "1":
|
|
count += 1
|
|
sink(r, c) # eat the whole island
|
|
return count
|
|
```
|
|
|
|
## Complexity
|
|
|
|
| | Time | Space |
|
|
|---|---|---|
|
|
| Tree DFS | O(n) | O(h) — call stack, h = height |
|
|
| Graph DFS | O(V + E) | O(V) |
|
|
|
|
Worst case h = n (a stick-shaped tree).
|
|
|
|
## Close-out ritual
|
|
|
|
Before you submit, say out loud:
|
|
1. Time and space complexity — name the call stack.
|
|
2. One edge case trace: null root, single node, or all-water grid.
|
|
|
|
## Plan problems
|
|
|
|
**Tree DFS A-set:** LC 226 · 104 · 100 · 572 · 236 · 124 ⭐
|
|
**Graph DFS A-set:** LC 200 · 695 · 133 · 417 · 130
|
|
**B-set:** LC 101 · 112 · 129 · 543 · 399 · 261
|