Skip to content
dsa450for five year olds

Binary Search Trees · 16 of 22

Count BST nodes that lie in a given range

Count the numbers in a sorted tree that fall between a low and a high mark, skipping whole branches that are sure to be too small or too big.

Simple way
time O(n)
room O(h)
Clever way
time O(h + k)
room O(h)

The problem, simply

You get a binary search tree (BST) and two numbers, low and high. Count how many numbers in the tree are between them, including low and high themselves.

A story to remember it

Picture it

tree
10550164010004570too bigtoo small

Range 5 to 45. Five numbers fit: 5, 6, 10, 40, 45. The branches under 1 on the left and under 50 on the right can be skipped without looking.

  • answer
  • ignored

Examples

A middle range

In
tree above, low = 5, high = 45
Out
5

5, 6, 10, 40 and 45. Both ends count.

Nothing fits

In
tree above, low = 11, high = 39
Out
0

10 is too small and 40 is too big, and nothing sits between them.

Everything fits

In
tree above, low = 0, high = 100
Out
10

Every number is inside, so we must visit all of them. No way can be faster than counting each one.

Low equals high

In
tree above, low = 40, high = 40
Out
1

Counting how many numbers equal 40.

Empty tree

In
[], low = 1, high = 9
Out
0

Nothing to count.

Way 1: the simple way

Visit every spot and check it.

  1. If the spot is null, return 0.
  2. Count 1 if low <= val <= high, else 0.
  3. Add the counts from both sides.
java
class Solution {
    public int countInRange(TreeNode root, int low, int high) {
        if (root == null) return 0;
        int here = (root.val >= low && root.val <= high) ? 1 : 0;
        return here + countInRange(root.left, low, high)
                    + countInRange(root.right, low, high);
    }
}

How long it takes: every spot, O(n). Extra room: the recursion, O(h). Correct on any tree, but it ignores the order.

Way 2: the clever way

Use the order to skip whole sides.

  1. If the spot is null, return 0.
  2. If val < low, this spot and its whole left side are too small. Only look at the right side.
  3. If val > high, this spot and its whole right side are too big. Only look at the left side.
  4. Otherwise count this spot and look at both sides.

Counting 5 to 45 and skipping branches

01 / 07

tree
10550164010004570curr
stack
count(10)top

10 is between 5 and 45. Count 1. Both sides might have more.

low
5
high
45
count
1
  • answer
  • rejected
  • ignored
java
class Solution {
    public int countInRange(TreeNode root, int low, int high) {
        if (root == null) return 0;
        if (root.val < low) return countInRange(root.right, low, high);   // left side is too small
        if (root.val > high) return countInRange(root.left, low, high);   // right side is too big
        return 1 + countInRange(root.left, low, high)                     // I fit
                 + countInRange(root.right, low, high);
    }
}

How long it takes: we visit the k spots that fit, plus at most two roads of spots that do not (one along the low edge, one along the high edge). So O(h + k). Extra room: the recursion, O(h).

Watch out for

  • Both ends count: use >= and <=.
  • A spot that is too small is not counted, but its right side might still hold numbers that fit. Do not stop there.
  • For the sum version (LeetCode 938, range sum of BST), add root.val instead of 1, and use long if the sum can be large.

What interviewers ask next

  • Return the numbers, not the count, in sorted order. Same pruning, but walk left side, me, right side and add to a list.
  • Many range questions on a fixed tree. Store in each spot the size of its part of the tree. Then "how many are <= high" is one road down, O(h), and the answer is countAtMost(high) - countAtMost(low - 1).
  • Remove every spot outside the range (LeetCode 669, trim a BST). Too small: return the trimmed right side. Too big: return the trimmed left side. Otherwise trim both children.
  • Count how many full subtrees lie entirely inside the range. Each spot returns whether its whole part fits. A part fits if both children's parts fit and the spot fits.

Remember this

Grown-up words: skipping whole sides is pruning, the low and high marks are the bounds of a range query, k is the size of the answer, and storing part sizes in each spot makes an order statistic tree.