DFS (Depth-First Search)

Use when: Explore all paths, detect cycles, connected components, tree traversals.

Complexity: O(V + E)

Recursive DFS (Graph)

def dfs(graph, node, visited):
    visited.add(node)
    for neighbor in graph[node]:
        if neighbor not in visited:
            dfs(graph, neighbor, visited)
 
visited = set()
dfs(graph, start, visited)

Iterative DFS (Graph)

def dfs_iterative(graph, start):
    visited = set()
    stack = [start]
 
    while stack:
        node = stack.pop()
        if node in visited:
            continue
        visited.add(node)
        for neighbor in graph[node]:
            if neighbor not in visited:
                stack.append(neighbor)

DFS - Grid

def dfs_grid(grid, r, c, visited):
    rows, cols = len(grid), len(grid[0])
    if r < 0 or r >= rows or c < 0 or c >= cols:
        return
    if (r, c) in visited:
        return
    visited.add((r, c))
    for dr, dc in [(0,1),(0,-1),(1,0),(-1,0)]:
        dfs_grid(grid, r + dr, c + dc, visited)

DFS - All Paths (with backtracking)

def dfs_paths(graph, node, target, path, result):
    if node == target:
        result.append(list(path))
        return
    for neighbor in graph[node]:
        path.append(neighbor)
        dfs_paths(graph, neighbor, target, path, result)
        path.pop()  # backtrack
 
result = []
dfs_paths(graph, start, target, [start], result)

Tree Traversals

def inorder(root):   # left → root → right
    return inorder(root.left) + [root.val] + inorder(root.right) if root else []
 
def preorder(root):  # root → left → right
    return [root.val] + preorder(root.left) + preorder(root.right) if root else []
 
def postorder(root): # left → right → root
    return postorder(root.left) + postorder(root.right) + [root.val] if root else []

Signals in a Problem

  • “All paths” / “all possibilities”
  • Connected components
  • Cycle detection
  • Tree path problems