Skip to content
← All posts

Range Sum of BST: Pruned DFS

5 min read
leetcodeproblemeasytrees

You are given the root of a binary search tree and two integers low and high. Return the sum of all node values that fall within the inclusive range [low, high].

This is LeetCode 938: Range Sum of BST, and it is a great problem for understanding how to exploit the BST property to skip entire subtrees during traversal.

range: [7, 15]10in range515in range37in range18sum = 7 + 10 + 15 = 32
Nodes 7, 10, and 15 fall within the range [7, 15] and contribute to the sum. Nodes 3, 5, and 18 are outside the range.

Why this is more than a simple traversal

You could solve this by visiting every node in the tree, checking if the value is in range, and adding it to a running sum. That works, but it ignores the most useful property of the data structure you are working with.

In a BST, every node in the left subtree has a smaller value than the current node, and every node in the right subtree has a larger value. That ordering gives you free information about which branches to skip.

If the current node's value is less than low, every node in its left subtree is also less than low. You do not need to visit any of them. If the current node's value is greater than high, every node in its right subtree is also greater than high. You can prune that entire branch too.

This is the same idea behind binary search: use the structure of sorted data to avoid looking at things you already know are irrelevant.

The approach: DFS with BST pruning

The algorithm is a recursive DFS that makes pruning decisions at each node:

  1. If the node is null, return 0 (base case).
  2. If node.val is less than low, skip the left subtree entirely and only recurse right.
  3. If node.val is greater than high, skip the right subtree entirely and only recurse left.
  4. If node.val is within [low, high], add it to the sum and recurse into both subtrees.

Here is the clean Python solution:

def range_sum_bst(root, low, high):
    if root is None:
        return 0
    if root.val < low:
        return range_sum_bst(root.right, low, high)
    if root.val > high:
        return range_sum_bst(root.left, low, high)
    return (root.val
            + range_sum_bst(root.left, low, high)
            + range_sum_bst(root.right, low, high))

Each recursive call either prunes a subtree or includes the current node and explores both children. The BST property ensures the pruning is always correct.

Step-by-step walkthrough

Let's trace through the example tree [10, 5, 15, 3, 7, null, 18] with low = 7 and high = 15.

Step 1: Visit root (10). 7 <= 10 <= 15, so add 10 to sum.

10add 105153718sum = 10

Node 10 is in range [7, 15]. Since 10 > 7, the left subtree might contain in-range nodes. Since 10 < 15, the right subtree might too. Explore both.

Step 2: Visit left child (5). 5 < 7, so skip it. But check its right subtree.

10+105skip153718sum = 10

Node 5 is below the range. We do not add it. Since 5 < 7, nothing in its left subtree can be >= 7 either, so prune left. But its right subtree might have values in range.

Step 3: Visit node 7. 7 >= 7 and 7 <= 15, so add 7 to sum.

10+105153pruned7add 718sum = 17

Node 7 is the left boundary of our range. It counts! Node 3 was pruned because the BST property guarantees everything left of 5 is less than 5, which is less than 7.

Step 4: Visit right child (15). 7 <= 15 <= 15, so add 15 to sum.

10+10515add 153pruned7+718sum = 32

Node 15 equals the upper bound and is in range. Since 15 >= 15, nothing in its right subtree can be <= 15, so we prune right. No left child to visit.

Step 5: Node 18 is pruned. DFS complete. Return 32.

10+10515+153pruned7+718prunedsum = 32

Node 18 > 15, so it is out of range and pruned. All paths explored. Final answer: 10 + 7 + 15 = 32.

Notice how node 3 and node 18 were never even considered for the sum. The BST property told us they could not possibly be in range, so we pruned those branches entirely. On larger trees, this pruning can save a significant amount of work.

Complexity analysis

MetricValue
TimeO(n) worst case, O(h + k) average
SpaceO(h) call stack

Time: In the worst case (every node is in range), you visit all n nodes, giving O(n). In practice, pruning reduces this. If the range is narrow, you visit roughly O(h + k) nodes where h is the tree height and k is the number of nodes in range.

Space: The recursion depth is bounded by the height of the tree. For a balanced BST, that is O(log n). For a completely skewed tree, it could be O(n).

The building blocks

This problem uses two fundamental ideas:

BST property exploitation. The ordering invariant of a BST (left subtree values are smaller, right subtree values are larger) lets you make decisions about entire subtrees without visiting them. This is the same property that makes BST search O(log n) instead of O(n). Any time you see a BST in a problem, ask yourself: can I use the ordering to skip work?

DFS traversal. The recursive structure follows the standard DFS template: handle the base case, process the current node, and recurse into children. The only twist here is that you conditionally recurse into one or both children based on the pruning logic. This conditional recursion pattern appears in many tree problems where you want to avoid exploring irrelevant branches.

Edge cases

  • Empty tree (root is None): return 0. The base case handles this directly.
  • Single node: if the node's value is in [low, high], return that value. Otherwise return 0.
  • All nodes in range: no pruning happens, and you visit every node. The algorithm still works correctly, it just does not get the pruning speedup.
  • No nodes in range: pruning cuts off early at every level. The function returns 0 after visiting only O(h) nodes along the pruning path.
  • low equals high: you are looking for a single value. The pruning narrows the search to a single root-to-leaf path, making this essentially a BST lookup.
  • Skewed tree (all nodes in a line): the call stack goes O(n) deep, but pruning still works. If the range is near the bottom of the chain, you skip the top portion. If it is near the top, you skip the bottom.

From understanding to recall

You just traced through how BST pruning lets you skip entire subtrees during a range sum. Right now, you can see exactly why checking node.val < low means "nothing to the left matters" and why node.val > high means "nothing to the right matters."

But when you face a BST problem in an interview next month, will you instinctively reach for the pruning optimization? Or will you write a brute-force traversal and miss the O(h + k) opportunity?

The pattern here is simple: if the current value is out of range on one side, only recurse into the other side. That is three lines of logic. But remembering to apply it under pressure requires practice. Spaced repetition helps you bridge the gap between understanding a technique today and recalling it automatically when you need it.

Related posts