BFS & DFS Patterns

Graph and tree traversal strategies

BFS & DFS Deep Dive

BFS explores level by level (queue-based), finding shortest paths in unweighted graphs. DFS explores as deep as possible first (stack/recursion-based), useful for topological sort, cycle detection, and backtracking.

typescript
// BFS/DFS Applications
// BFS: Level Order Traversal of Binary Tree
function levelOrder(root: TreeNode<number> | null): number[][] {
  if (!root) return [];
  const result: number[][] = [];
  const queue: TreeNode<number>[] = [root];
  while (queue.length) {
    const level: number[] = [];
    const size = queue.length;
    for (let i = 0; i < size; i++) {
      const node = queue.shift()!;
      level.push(node.val);
      if (node.left) queue.push(node.left);
      if (node.right) queue.push(node.right);
    }
    result.push(level);
  }
  return result;
}

// Topological Sort using DFS
function topologicalSort(n: number, edges: [number, number][]): number[] {
  const adj: number[][] = Array.from({ length: n }, () => []);
  for (const [u, v] of edges) adj[u].push(v);
  
  const visited = new Set<number>();
  const stack: number[] = [];
  
  function dfs(node: number, visiting: Set<number>): boolean {
    if (visiting.has(node)) return false; // cycle
    if (visited.has(node)) return true;
    visiting.add(node);
    for (const neighbor of adj[node]) {
      if (!dfs(neighbor, visiting)) return false;
    }
    visiting.delete(node);
    visited.add(node);
    stack.push(node);
    return true;
  }
  
  for (let i = 0; i < n; i++) {
    if (!visited.has(i) && !dfs(i, new Set())) return []; // cycle exists
  }
  return stack.reverse();
}

class TreeNode<T> {
  val: T;
  left: TreeNode<T> | null = null;
  right: TreeNode<T> | null = null;
  constructor(val: T) { this.val = val; }
}