questions A (01-matrix - avoid-flood)

This commit is contained in:
2025-05-24 21:40:39 +01:00
parent 09ec96a282
commit 0b83eff6f8
55 changed files with 10813 additions and 0 deletions

View File

@@ -0,0 +1,214 @@
title: All Elements in Two Binary Search Trees
slug: all-elements-in-two-binary-search-trees
difficulty: medium
leetcode_id: 1305
leetcode_url: https://leetcode.com/problems/all-elements-in-two-binary-search-trees/
categories:
- trees
- sorting
patterns:
- tree-traversal
- two-pointers
description: |
Given two binary search trees `root1` and `root2`, return *a list containing all the integers from both trees sorted in **ascending** order*.
constraints: |
- The number of nodes in each tree is in the range `[0, 5000]`
- `-10^5 <= Node.val <= 10^5`
examples:
- input: "root1 = [2,1,4], root2 = [1,0,3]"
output: "[0,1,1,2,3,4]"
explanation: "Tree 1 contains [1,2,4] and tree 2 contains [0,1,3]. Merged in sorted order: [0,1,1,2,3,4]."
- input: "root1 = [1,null,8], root2 = [8,1]"
output: "[1,1,8,8]"
explanation: "Tree 1 contains [1,8] and tree 2 contains [1,8]. Merged in sorted order: [1,1,8,8]."
explanation:
intuition: |
The key insight is recognising that **binary search trees have a special property**: an in-order traversal (left → node → right) visits nodes in sorted ascending order.
Think of it like this: each BST is already a "sorted container" in disguise. If you perform an in-order traversal, you get a sorted list for free. So the problem transforms into: **merge two sorted lists into one sorted list**.
This is exactly the merge step from merge sort! You compare the front elements of both lists and take the smaller one, repeating until both lists are exhausted.
The elegant solution combines these two insights:
1. Use BST's in-order property to extract sorted sequences
2. Use two-pointer merge to combine them efficiently
approach: |
We solve this using **In-Order Traversal + Two-Pointer Merge**:
**Step 1: Perform in-order traversal on both trees**
- Traverse each BST using in-order DFS (left → node → right)
- This produces two sorted lists: `list1` from `root1` and `list2` from `root2`
- Each traversal is O(n) time and produces elements in ascending order
&nbsp;
**Step 2: Merge the two sorted lists**
- Use two pointers, `i` for `list1` and `j` for `list2`
- Compare `list1[i]` and `list2[j]`, append the smaller to the result
- Advance the pointer of whichever list contributed the element
- Continue until one list is exhausted
&nbsp;
**Step 3: Handle remaining elements**
- If `list1` has remaining elements, append them all
- If `list2` has remaining elements, append them all
- One list may be longer or one tree may be empty
&nbsp;
**Step 4: Return the merged result**
- The result list contains all elements from both trees in sorted order
common_pitfalls:
- title: Forgetting the BST Property
description: |
A common mistake is to collect all values from both trees and then sort the combined list.
While this works, it's inefficient: sorting takes O((m+n) log(m+n)) time. By leveraging the BST's in-order property, we get sorted lists in O(m+n) time, and merging is also O(m+n). This is asymptotically better.
wrong_approach: "Collect all values, then sort with sorted() or list.sort()"
correct_approach: "In-order traversal gives sorted lists, then merge in O(m+n)"
- title: Not Handling Empty Trees
description: |
Either `root1` or `root2` (or both) could be empty trees. Your in-order traversal should handle `None` roots gracefully by returning an empty list.
The merge step naturally handles this since merging with an empty list just returns the other list.
wrong_approach: "Assuming both trees have at least one node"
correct_approach: "Check for None roots, return empty list from traversal"
- title: Inefficient Merge with List Concatenation
description: |
Using `result = result + [value]` inside a loop creates a new list each iteration, leading to O(n²) time complexity.
Use `result.append(value)` which is O(1) amortized, keeping the merge at O(m+n).
wrong_approach: "result = result + [smaller_value] in loop"
correct_approach: "result.append(smaller_value)"
key_takeaways:
- "**BST in-order property**: In-order traversal of a BST always produces elements in sorted ascending order"
- "**Problem transformation**: Recognise when a problem can be reduced to a simpler, well-known problem (merge two sorted lists)"
- "**Two-pointer merge**: The merge step from merge sort is a fundamental pattern for combining sorted sequences"
- "**Foundation for harder problems**: This pattern extends to problems like merge k sorted lists, external sorting, and stream merging"
time_complexity: "O(m + n). We traverse each tree once (O(m) + O(n)) and merge the two lists once (O(m + n)), where m and n are the number of nodes in each tree."
space_complexity: "O(m + n). We store all elements from both trees in lists, plus O(h1 + h2) recursion stack space for the traversals, where h1 and h2 are the tree heights."
solutions:
- approach_name: In-Order Traversal + Merge
is_optimal: true
code: |
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def get_all_elements(root1: TreeNode, root2: TreeNode) -> list[int]:
def inorder(root: TreeNode) -> list[int]:
"""In-order traversal returns BST values in sorted order."""
if not root:
return []
# Left subtree + current node + right subtree
return inorder(root.left) + [root.val] + inorder(root.right)
# Get sorted lists from both BSTs
list1 = inorder(root1)
list2 = inorder(root2)
# Merge two sorted lists using two pointers
result = []
i, j = 0, 0
while i < len(list1) and j < len(list2):
if list1[i] <= list2[j]:
result.append(list1[i])
i += 1
else:
result.append(list2[j])
j += 1
# Append remaining elements from either list
result.extend(list1[i:])
result.extend(list2[j:])
return result
explanation: |
**Time Complexity:** O(m + n) — In-order traversal is O(m) + O(n), merge is O(m + n).
**Space Complexity:** O(m + n) — We store all elements plus recursion stack.
We leverage the BST property that in-order traversal produces sorted output. Then we apply the classic two-pointer merge from merge sort to combine the two sorted lists efficiently.
- approach_name: Iterative In-Order with Stack
is_optimal: true
code: |
def get_all_elements(root1: TreeNode, root2: TreeNode) -> list[int]:
result = []
stack1, stack2 = [], []
# Helper to push all left children onto stack
def push_left(node, stack):
while node:
stack.append(node)
node = node.left
# Initialise stacks with leftmost paths
push_left(root1, stack1)
push_left(root2, stack2)
while stack1 or stack2:
# Choose which stack to pop from
if not stack2 or (stack1 and stack1[-1].val <= stack2[-1].val):
# Pop from stack1
node = stack1.pop()
result.append(node.val)
# Push left path of right child
push_left(node.right, stack1)
else:
# Pop from stack2
node = stack2.pop()
result.append(node.val)
push_left(node.right, stack2)
return result
explanation: |
**Time Complexity:** O(m + n) — Each node is pushed and popped exactly once.
**Space Complexity:** O(h1 + h2) — Only stores nodes on the current paths (tree heights).
This approach interleaves the in-order traversals, avoiding the need to materialise both full lists. We maintain two stacks representing the "frontier" of each traversal, always taking the smaller current element.
- approach_name: Collect and Sort
is_optimal: false
code: |
def get_all_elements(root1: TreeNode, root2: TreeNode) -> list[int]:
def collect(root: TreeNode, values: list[int]):
"""Collect all values from tree (any order)."""
if not root:
return
values.append(root.val)
collect(root.left, values)
collect(root.right, values)
values = []
collect(root1, values)
collect(root2, values)
# Sort all collected values
return sorted(values)
explanation: |
**Time Complexity:** O((m + n) log(m + n)) — Dominated by the sorting step.
**Space Complexity:** O(m + n) — Stores all elements.
This approach ignores the BST property and simply collects all values, then sorts. While correct and simple, it's less efficient than leveraging the inherent ordering of BSTs. Included to illustrate why understanding data structure properties matters.