Code Templates
Depth-First Search
Use Cases
Use Case | Description | Example |
---|---|---|
Preorder Traversal of a Binary Tree | Given a binary tree, return the values of its nodes in preorder (root, left, right) traversal. | For the tree: 1, with children 2 and 3, and 2's children 4 and 5. The result is [1, 2, 4, 5, 3]. |
Finding All Paths from Root to Leaves | Find all paths from the root to each leaf node in the binary tree. | For the tree: 1 with children 2 and 3, and 2's children 4 and 5. The result is [[1, 2, 4], [1, 2, 5], [1, 3]]. |
Checking for Symmetry of a Binary Tree | Check if the binary tree is symmetric around its center. | For the tree: 1 with children 2 and 2 (both having children 3 and 3). The result is True (symmetric). |
Code Template
Basic case
dfs()
takes two parameters: root (the current node) and result (a list to store node values).if not root:
checks if the current node is None. If it is, the function returns immediately.
Collect node value
- It collects node values during the DFS traversal, helping to track the order of processed nodes.
Loop over queue
- Recursively calls
dfs()
on each child, allowing traversal of both subtrees.
def dfs(root, result):if not root:return
Common mistakes
- Wrong Base Case
# Wrong: missing base casedef dfs(root, result):result.append(root.val) # Will fail on None# Wrong: wrong return valuedef dfs(root, result):if not root:return result # Should return None# Correct:if not root:return
Issues and consideration
BFS VS DFS:
BFS is ideal for scenarios where you need the shortest path or to explore nodes level by level. DFS is better suited for problems that require exploring all possible options or paths, especially when the solution is deep in the tree or graph.
Related Problem
class Solution:def isBalanced(self, root: Optional[TreeNode]) -> bool:def dfs(node):if not node:return 0left = dfs(node.left)right = dfs(node.right)# -1 indicates unbalanced subtreeif left == -1 or right == -1 or abs(left - right) > 1:return -1return max(left, right) + 1return dfs(root) != -1
144. Binary Tree Preorder Traversal
class Solution:def preorderTraversal(self, root: TreeNode) -> List[int]:def dfs(node):if not node:returnresult.append(node.val)for child in (node.left, node.right):dfs(child)result = []dfs(root)return result
class Solution:def hasPathSum(self, root: TreeNode, targetSum: int) -> bool:def dfs(node, currentSum):if not node:return FalsecurrentSum += node.val # Add current node's value# Check if it's a leaf node and sum matchesif not node.left and not node.right:return currentSum == targetSum# Continue DFS on childrenfor child in (node.left, node.right):if dfs(child, currentSum):return Truereturn Falsereturn dfs(root, 0)
class Solution:def numIslands(self, grid: List[List[str]]) -> int:def dfs(r, c):if (r < 0 or r >= rows orc < 0 or c >= cols orgrid[r][c] != '1'):return# Mark as visitedgrid[r][c] = '#'# Visit all adjacent cellsfor nr, nc in [(r+1,c), (r-1,c), (r,c+1), (r,c-1)]:dfs(nr, nc)if not grid:return 0rows, cols = len(grid), len(grid[0])count = 0for r in range(rows):for c in range(cols):if grid[r][c] == '1':dfs(r, c)count += 1return count
class Solution:def diameterOfBinaryTree(self, root: Optional[TreeNode]) -> int:def dfs(node):if not node:return 0left = dfs(node.left)right = dfs(node.right)# Update diameter if path through current node is longerself.diameter = max(self.diameter, left + right)# Return height of current subtreereturn max(left, right) + 1self.diameter = 0dfs(root)return self.diameter