Skip to content
dsa450for five year olds

Binary Search Trees · 12 of 22

Find Kth largest element in a BST

Count down through a sorted tree from the biggest number and stop at the k-th one, by mirroring the usual left-to-right walk.

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

The problem, simply

You get a binary search tree (BST) and a number k, counting from 1. Give back the k-th largest number. For k = 1 that is the biggest number, for k = 2 the second biggest, and so on.

A story to remember it

Picture it

tree
841226101413574th2nd3rd1st5th
arraybiggest first
01234567891014121087654321k=5

Read the tree right side, me, left side and you get 14, 12, 10, 8, 7, 6, 5, 4, 3, 2, 1. The 5th one is 7.

  • answer

Examples

Across the top

In
tree above, k = 5
Out
7

14, 12, 10, 8, and then the biggest on the left side of 8, which is 7.

The biggest

In
tree above, k = 1
Out
14

Slide all the way right.

The smallest

In
tree above, k = 11
Out
1

k equals the number of spots. The k-th largest is the smallest.

A stick going left

In
[3, 2, null, 1], k = 2
Out
2

The biggest is the top, 3. It has no right side, so the second biggest is the next spot down the left, 2.

Way 1: the simple way

Write the sorted order down, smallest first, and count back from the end.

  1. Visit left side, me, right side and add each number to a list.
  2. The k-th largest is at position size - k.
java
import java.util.*;

class Solution {
    public int kthLargest(TreeNode root, int k) {
        List<Integer> sorted = new ArrayList<>();
        inorder(root, sorted);
        return sorted.get(sorted.size() - k);
    }

    private void inorder(TreeNode node, List<Integer> sorted) {
        if (node == null) return;
        inorder(node.left, sorted);
        sorted.add(node.val);
        inorder(node.right, sorted);
    }
}

How long it takes: every spot, O(n). Extra room: the list, O(n).

Way 2: the clever way

Walk biggest first with a pile, and stop at the k-th pop. It is the kth smallest walk with left and right swapped.

  1. Push the right road from the top: the top, its right child, that one's right child, and so on.
  2. Pop the pile. That is the next biggest number. Count it.
  3. If the count is k, return it.
  4. Otherwise push the right road starting from the popped spot's left child, and repeat.

Count down to k = 5 with a pile

01 / 06

tree
84122610141357
stackpile
81214top

Push the right road: 8, 12, 14. The top of the pile, 14, is the biggest number.

count
0
k
5
  • looking now
  • done
  • answer
  • path
  • just added
  • ignored
java
import java.util.*;

class Solution {
    public int kthLargest(TreeNode root, int k) {
        Deque<TreeNode> pile = new ArrayDeque<>();
        TreeNode curr = root;
        while (curr != null || !pile.isEmpty()) {
            while (curr != null) {          // push the right road
                pile.push(curr);
                curr = curr.right;
            }
            curr = pile.pop();              // the next biggest
            if (--k == 0) return curr.val;
            curr = curr.left;               // its left side comes next
        }
        return -1;                          // k is bigger than the tree
    }
}

How long it takes: h steps down the first right road, then k pops, O(h + k). Extra room: the pile, O(h).

Another way: recursion with a shared counter

The same walk written as recursion. The counter must live outside the calls so that all of them share it.

java
class Solution {
    private int left, answer;

    public int kthLargest(TreeNode root, int k) {
        left = k;
        answer = -1;
        walk(root);
        return answer;
    }

    private void walk(TreeNode node) {
        if (node == null || left == 0) return;   // stop early once found
        walk(node.right);
        if (left == 0) return;
        if (--left == 0) { answer = node.val; return; }
        walk(node.left);
    }
}

Same O(h + k) time and O(h) room for the call stack.

Watch out for

  • Swapping only one of the two directions in Way 2. Push the right road, and after a pop move to the left child. Swapping just one gives a wrong order.
  • A counter passed as a plain int parameter in recursion. Each call gets its own copy.
  • k bigger than the tree, or k <= 0. Decide what to return.

What interviewers ask next

  • Do it with O(1) room. Use a mirrored Morris walk: before going right from a spot, find the smallest spot on its right side (right once, then left as far as you can) and point that spot's empty left arrow back up, like a rope. Climb back by the rope, untie it, count the spot, then go left. Untie any ropes left behind if you stop early.
  • Many questions on a changing tree. Store subtree sizes in each spot, then the k-th largest is the (n - k + 1)-th smallest, found in O(h).
  • k-th largest in a stream of numbers (LeetCode 703). Keep a min heap of the k biggest seen so far. Its top is the answer.
  • Sum of the k biggest numbers. Same walk, add instead of only counting.

Remember this

Grown-up words: right, me, left is a reverse inorder traversal, the pile is the stack of an iterative traversal, the shared counter is a field shared across recursive calls, and O(h + k) means the height to start plus k pops.