Algorithm Templates: DFS
Minimal, copy-paste Python for graph DFS, grid DFS, tree DFS, memoization, and iterative DFS. See also Graph and Backtracking.
Contents
Basic DFS
Depth-First Search explores as far as possible before backtracking.
# DFS on graph (adjacency list)
def dfs_graph(graph: list[list[int]], node: int, visited: list[bool]) -> None:
visited[node] = True
# process node
for neighbor in graph[node]:
if not visited[neighbor]:
dfs_graph(graph, neighbor, visited)
def dfs_find_target(
graph: list[list[int]], node: int, target: int, visited: list[bool]
) -> bool:
if node == target:
return True
visited[node] = True
for neighbor in graph[node]:
if not visited[neighbor] and dfs_find_target(graph, neighbor, target, visited):
return True
return False
DFS on Grid
DFS for 2D grid problems (connected components, paths).
# DFS on 2D grid (4-directional)
DIRS = [(0, 1), (0, -1), (1, 0), (-1, 0)]
def dfs_grid(grid: list[list[str]], i: int, j: int) -> None:
m, n = len(grid), len(grid[0])
if i < 0 or i >= m or j < 0 or j >= n or grid[i][j] != "1":
return
grid[i][j] = "0"
for di, dj in DIRS:
dfs_grid(grid, i + di, j + dj)
def num_islands(grid: list[list[str]]) -> int:
m, n = len(grid), len(grid[0])
count = 0
for i in range(m):
for j in range(n):
if grid[i][j] == "1":
count += 1
dfs_grid(grid, i, j)
return count
def dfs_word_search(board: list[list[str]], i: int, j: int, word: str, idx: int) -> bool:
if idx == len(word):
return True
if i < 0 or i >= len(board) or j < 0 or j >= len(board[0]):
return False
if board[i][j] != word[idx]:
return False
temp = board[i][j]
board[i][j] = "#"
for di, dj in DIRS:
if dfs_word_search(board, i + di, j + dj, word, idx + 1):
board[i][j] = temp
return True
board[i][j] = temp
return False
| ID | Title | Link | Solution |
|---|---|---|---|
| 200 | Number of Islands | Link | Solution |
| 79 | Word Search | Link | Solution |
| 695 | Max Area of Island | Link | Solution |
| 133 | Clone Graph | Link | Solution |
| 417 | Pacific Atlantic Water Flow | Link | Solution |
| 323 | Number of Connected Components | Link | Solution |
| 547 | Number of Provinces | Link | Solution |
DFS on Tree
DFS for tree problems (preorder, inorder, postorder).
class TreeNode:
def __init__(self, val: int = 0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def preorder(root: TreeNode | None, result: list[int]) -> None:
if not root:
return
result.append(root.val)
preorder(root.left, result)
preorder(root.right, result)
def inorder(root: TreeNode | None, result: list[int]) -> None:
if not root:
return
inorder(root.left, result)
result.append(root.val)
inorder(root.right, result)
def postorder(root: TreeNode | None, result: list[int]) -> None:
if not root:
return
postorder(root.left, result)
postorder(root.right, result)
result.append(root.val)
def has_path_sum(root: TreeNode | None, target_sum: int) -> bool:
if not root:
return False
if not root.left and not root.right:
return root.val == target_sum
return has_path_sum(root.left, target_sum - root.val) or has_path_sum(
root.right, target_sum - root.val
)
def sum_numbers(root: TreeNode | None, cur: int = 0) -> int:
if not root:
return 0
cur = cur * 10 + root.val
if not root.left and not root.right:
return cur
return sum_numbers(root.left, cur) + sum_numbers(root.right, cur)
| ID | Title | Link | Solution |
|---|---|---|---|
| 100 | Same Tree | Link | Solution |
| 101 | Symmetric Tree | Link | Solution |
| 104 | Maximum Depth of Binary Tree | Link | Solution |
| 111 | Minimum Depth of Binary Tree | Link | Solution |
| 112 | Path Sum | Link | Solution |
| 129 | Sum Root to Leaf Numbers | Link | Solution |
| 226 | Invert Binary Tree | Link | Solution |
| 236 | Lowest Common Ancestor | Link | Solution |
| 437 | Path Sum III | Link | Solution |
| 690 | Employee Importance | Link | Solution |
DFS with Memoization
DFS with caching to avoid recomputation.
DIRS4 = [(0, 1), (0, -1), (1, 0), (-1, 0)]
def dfs_with_memo(
matrix: list[list[int]], i: int, j: int, memo: list[list[int]], prev: int
) -> int:
m, n = len(matrix), len(matrix[0])
if i < 0 or i >= m or j < 0 or j >= n or matrix[i][j] <= prev:
return 0
if memo[i][j] != -1:
return memo[i][j]
best = 1
for di, dj in DIRS4:
best = max(best, 1 + dfs_with_memo(matrix, i + di, j + dj, memo, matrix[i][j]))
memo[i][j] = best
return best
| ID | Title | Link | Solution |
|---|---|---|---|
| 329 | Longest Increasing Path in a Matrix | Link | Solution |
Iterative DFS
DFS using stack instead of recursion.
class TreeNode:
def __init__(self, val: int = 0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def dfs_iterative(graph: list[list[int]], start: int) -> None:
st: list[int] = [start]
visited = [False] * len(graph)
while st:
node = st.pop()
if visited[node]:
continue
visited[node] = True
for nei in reversed(graph[node]):
if not visited[nei]:
st.append(nei)
def preorder_iterative(root: TreeNode | None) -> list[int]:
if not root:
return []
result: list[int] = []
st: list[TreeNode] = [root]
while st:
node = st.pop()
result.append(node.val)
if node.right:
st.append(node.right)
if node.left:
st.append(node.left)
return result
| ID | Title | Link | Solution |
|---|---|---|---|
| 144 | Binary Tree Preorder Traversal | Link | - |
| 94 | Binary Tree Inorder Traversal | Link | - |
More templates
- Graph, Backtracking: Graph, Backtracking
- Data structures, Search: Data Structures & Core Algorithms, Search
- Master index: Categories & Templates