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
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.
- Visit left side, me, right side and add each number to a list.
- The
k-th largest is at positionsize - k.
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.
- Push the right road from the top: the top, its right child, that one's right child, and so on.
- Pop the pile. That is the next biggest number. Count it.
- If the count is
k, return it. - 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
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
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.
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
intparameter in recursion. Each call gets its own copy. kbigger than the tree, ork <= 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 emptyleftarrow 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 inO(h). k-th largest in a stream of numbers (LeetCode 703). Keep a min heap of thekbiggest seen so far. Its top is the answer.- Sum of the
kbiggest 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.