medium tree, graph, dp questions

This commit is contained in:
2025-04-28 23:04:27 +01:00
parent 9e04184b40
commit 877ef2fe30
4 changed files with 541 additions and 0 deletions

View File

@@ -0,0 +1,135 @@
title: Binary Tree Level Order Traversal
slug: binary-tree-level-order
difficulty: medium
leetcode_id: 102
leetcode_url: https://leetcode.com/problems/binary-tree-level-order-traversal/
categories:
- trees
- queue
patterns:
- bfs
description: |
Given the `root` of a binary tree, return the level order traversal of its nodes' values
(i.e., from left to right, level by level).
constraints: |
- The number of nodes in the tree is in the range [0, 2000].
- -1000 <= Node.val <= 1000
examples:
- input: "root = [3,9,20,null,null,15,7]"
output: "[[3],[9,20],[15,7]]"
explanation: "Level 0 has 3, level 1 has 9 and 20, level 2 has 15 and 7."
- input: "root = [1]"
output: "[[1]]"
explanation: "Single node at level 0."
- input: "root = []"
output: "[]"
explanation: "Empty tree returns empty list."
explanation:
approach: |
1. Use a queue for BFS traversal
2. Track the number of nodes at current level
3. Process all nodes at current level before moving to next
4. Add children to queue as we process each node
5. Collect values for each level in a separate list
intuition: |
BFS naturally visits nodes level by level. By tracking how many nodes are in the queue
at the start of each level, we know exactly when one level ends and the next begins.
The key insight is that after processing all nodes of level k, the queue contains
exactly all nodes of level k+1.
common_pitfalls:
- title: Not tracking level boundaries
description: |
Without tracking level size, you can't separate nodes into their levels.
Capture queue size at the start of each level iteration.
wrong_approach: "Processing queue without counting level size"
correct_approach: "level_size = len(queue); process level_size nodes"
- title: Forgetting null check
description: |
Empty tree (null root) should return empty list, not cause an error.
- title: Using list as queue
description: |
Using list.pop(0) is O(n). Use collections.deque for O(1) popleft.
key_takeaways:
- BFS with queue is the standard for level-order traversal
- Track level size to group nodes by level
- This pattern extends to many tree problems (zigzag, right side view, etc.)
- deque is more efficient than list for queue operations
time_complexity: "O(n)"
space_complexity: "O(n)"
complexity_explanation: |
Time: Visit each node exactly once.
Space: Queue holds at most one level of nodes, which is O(n) in worst case (complete tree).
solutions:
- approach_name: BFS with Queue (Optimal)
is_optimal: true
code: |
from collections import deque
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def level_order(root: TreeNode | None) -> list[list[int]]:
if not root:
return []
result = []
queue = deque([root])
while queue:
level_size = len(queue)
level_values = []
for _ in range(level_size):
node = queue.popleft()
level_values.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
result.append(level_values)
return result
explanation: |
Process nodes level by level using a queue.
Track level size to know when to start a new level list.
- approach_name: DFS with Level Tracking
is_optimal: false
code: |
def level_order(root: TreeNode | None) -> list[list[int]]:
result = []
def dfs(node: TreeNode | None, level: int) -> None:
if not node:
return
if level == len(result):
result.append([])
result[level].append(node.val)
dfs(node.left, level + 1)
dfs(node.right, level + 1)
dfs(root, 0)
return result
explanation: |
DFS alternative: pass level as parameter and append to appropriate list.
Same time complexity but uses recursion stack space.