Two Sum in BST in DSA Go - Time & Space Complexity
We want to know how the time needed to find two numbers that add up to a target grows as the tree gets bigger.
How does the search time change when the number of nodes in the BST increases?
Analyze the time complexity of the following code snippet.
func findTarget(root *TreeNode, k int) bool {
seen := make(map[int]bool)
var dfs func(node *TreeNode) bool
dfs = func(node *TreeNode) bool {
if node == nil {
return false
}
if seen[k - node.Val] {
return true
}
seen[node.Val] = true
return dfs(node.Left) || dfs(node.Right)
}
return dfs(root)
}
This code searches the BST to find if there are two nodes whose values add up to k using a depth-first search and a map to track seen values.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Recursive traversal of each node in the BST.
- How many times: Each node is visited once during the DFS.
As the number of nodes (n) grows, the function visits each node once, so the operations grow roughly in direct proportion to n.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 visits |
| 100 | About 100 visits |
| 1000 | About 1000 visits |
Pattern observation: The operations increase linearly as the tree size increases.
Time Complexity: O(n)
This means the time to find the two sum grows linearly with the number of nodes in the BST.
[X] Wrong: "Because the tree is a BST, searching for pairs is O(log n)."
[OK] Correct: The code visits every node once to check pairs, so it must look at all nodes, making it linear, not logarithmic.
Understanding this linear time complexity helps you explain how tree traversal and hash maps work together to solve problems efficiently.
"What if we used an in-order traversal to create a sorted list first, then used two pointers to find the sum? How would the time complexity change?"
Practice
Two Sum in BST problem?Solution
Step 1: Understand the problem statement
The problem asks to find two nodes in a Binary Search Tree (BST) such that their values add up to a given target sum.Step 2: Identify the goal
The goal is to check if such a pair exists, not to find max, count nodes, or check balance.Final Answer:
Find two nodes in the BST whose values add up to a given target sum. -> Option BQuick Check:
Two Sum in BST = Find pair with target sum [OK]
- Confusing with finding max or min value
- Trying to count nodes instead of finding pairs
- Checking BST balance instead of sum pairs
Solution
Step 1: Understand function parameters and return type
The function should take a pointer to the root node of BST and an integer target sum, returning a boolean indicating if pair exists.Step 2: Match correct signature
func findTarget(root *TreeNode, k int) bool matches: pointer to TreeNode, integer target, returns bool.Final Answer:
func findTarget(root *TreeNode, k int) bool -> Option AQuick Check:
Correct function signature = func findTarget(root *TreeNode, k int) bool [OK]
- Using wrong parameter types like string or bool
- Passing TreeNode by value instead of pointer
- Returning wrong type like int or string
type TreeNode struct {
Val int
Left, Right *TreeNode
}
func findTarget(root *TreeNode, k int) bool {
seen := make(map[int]bool)
var dfs func(*TreeNode) bool
dfs = func(node *TreeNode) bool {
if node == nil {
return false
}
if seen[k - node.Val] {
return true
}
seen[node.Val] = true
return dfs(node.Left) || dfs(node.Right)
}
return dfs(root)
}
root := &TreeNode{Val:5, Left:&TreeNode{Val:3}, Right:&TreeNode{Val:6}}
result := findTarget(root, 9)
fmt.Println(result)Solution
Step 1: Trace the DFS traversal and map usage
The function uses DFS to traverse nodes. It checks if (target - current node value) is in the map. For root 5, seen is empty, adds 5. Goes left to 3, checks if 9-3=6 in seen (no), adds 3. Goes right to 6, checks if 9-6=3 in seen (yes), returns true.Step 2: Confirm output
Since pair (3,6) sums to 9, function returns true and prints true.Final Answer:
true -> Option AQuick Check:
Pair found (3+6=9) = true [OK]
- Not checking complement before adding current value
- Returning false too early
- Ignoring nil node checks causing panic
func findTarget(root *TreeNode, k int) bool {
seen := make(map[int]bool)
var dfs func(*TreeNode) bool
dfs = func(node *TreeNode) bool {
if node == nil {
return false
}
seen[node.Val] = true
if seen[k - node.Val] {
return true
}
return dfs(node.Left) || dfs(node.Right)
}
return dfs(root)
}Solution
Step 1: Analyze the order of operations in DFS
The code adds current node value to map before checking if complement exists. This causes the complement check to always find current value, leading to false positives.Step 2: Correct the order
Check if complement exists in map before adding current node value to avoid matching the same node twice.Final Answer:
Check complement before adding current node value to map. -> Option DQuick Check:
Complement check before map insert fixes bug [OK]
- Adding current value before checking complement
- Using wrong data structure for lookup
- Ignoring nil node checks
func findAllPairs(root *TreeNode, k int) [][2]int {
seen := make(map[int]bool)
pairs := [][2]int{}
var dfs func(*TreeNode)
dfs = func(node *TreeNode) {
if node == nil {
return
}
complement := k - node.Val
if seen[complement] {
pairs = append(pairs, [2]int{complement, node.Val})
}
seen[node.Val] = true
dfs(node.Left)
dfs(node.Right)
}
dfs(root)
return pairs
}Solution
Step 1: Identify all pairs in BST that sum to 9
Nodes are 1,2,3,4,5,6,7. Pairs summing to 9 are (2,7), (3,6), (4,5).Step 2: Match pairs with function output format
The function appends pairs as [complement, node.Val] during preorder traversal: at 6 finds 3 in seen, appends [3,6]; at 5 finds 4, [4,5]; at 7 finds 2, [2,7].Final Answer:
[[3,6],[4,5],[2,7]] -> Option CQuick Check:
Pairs summing to 9 in traversal order = [[3,6],[4,5],[2,7]] [OK]
- Including pairs with values not in BST
- Reversing pair order incorrectly
- Missing valid pairs
Ready to prove it?
Pass the test and this pattern moves unknown
