Binary Search TreesProblem 12 of 22
Find Kth largest element in a BST
Problem Statement
Given a BST and a positive integer k, find the kth largest element in the BST.
Example:
5
/ \
3 6
/ \
2 4
/
1
k = 2
Output: 5 (Elements in desc order: 6, 5, 4, 3, 2, 1)
k = 4
Output: 3
Approach 1: Brute Force (Inorder + Find kth from End)
Intuition
Inorder traversal gives sorted order. The kth largest is the (n-k+1)th element or simply the kth element from the end.
Algorithm
- Perform inorder traversal to get sorted array
- Return array[n - k] (0-indexed) which is kth largest
java
import java.util.*;
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int x) { val = x; }
}
public class Solution {
private void inorder(TreeNode root, List<Integer> nodes) {
if (root == null) return;
inorder(root.left, nodes);
nodes.add(root.val);
inorder(root.right, nodes);
}
public int kthLargestBruteForce(TreeNode root, int k) {
List<Integer> nodes = new ArrayList<>();
inorder(root, nodes);
if (k > nodes.size() || k <= 0) {
return -1; // Invalid k
}
return nodes.get(nodes.size() - k);
}
}Complexity Analysis
- Time Complexity: O(n) - Complete traversal
- Space Complexity: O(n) - Storing all nodes
Approach 2: Optimal (Reverse Inorder Traversal)
Intuition
Reverse inorder (right -> root -> left) visits nodes in descending order. Stop when we reach the kth node.
Algorithm
- Perform reverse inorder traversal
- Count nodes visited
- When count equals k, record the result
- Use early termination to avoid unnecessary traversal
java
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int x) { val = x; }
}
public class Solution {
private int count = 0;
private int result = -1;
private void reverseInorder(TreeNode root, int k) {
if (root == null || count >= k) return;
// Traverse right subtree first (larger values)
reverseInorder(root.right, k);
// Process current node
count++;
if (count == k) {
result = root.val;
return;
}
// Traverse left subtree
reverseInorder(root.left, k);
}
public int kthLargest(TreeNode root, int k) {
count = 0;
result = -1;
reverseInorder(root, k);
return result;
}
}Complexity Analysis
- Time Complexity: O(h + k) - Traverse to rightmost then k nodes
- Space Complexity: O(h) - Recursion stack
Approach 3: Iterative (Morris-like with Stack)
Intuition
Use iterative reverse inorder with explicit stack for O(h) space.
Algorithm
- Use stack to simulate reverse inorder
- Push right nodes first, then process, then go left
- Stop at kth node
java
import java.util.*;
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int x) { val = x; }
}
public class Solution {
public int kthLargestIterative(TreeNode root, int k) {
Stack<TreeNode> stack = new Stack<>();
TreeNode curr = root;
int count = 0;
while (curr != null || !stack.isEmpty()) {
// Go to rightmost
while (curr != null) {
stack.push(curr);
curr = curr.right;
}
curr = stack.pop();
count++;
if (count == k) {
return curr.val;
}
curr = curr.left;
}
return -1; // k is larger than tree size
}
}Complexity Analysis
- Time Complexity: O(h + k)
- Space Complexity: O(h) - Stack space
Approach 4: Using Augmented BST (For Multiple Queries)
Intuition
If we need to answer multiple kth largest/smallest queries, augment each node with the count of nodes in its subtree.
Algorithm
- Augment each node with size of its subtree
- For kth largest: k nodes from the right
- Use subtree sizes to navigate efficiently
java
class AugmentedNode {
int val;
int leftCount; // Number of nodes in left subtree
AugmentedNode left, right;
AugmentedNode(int x) { val = x; leftCount = 0; }
}
public class Solution {
private int countNodes(AugmentedNode root) {
if (root == null) return 0;
return 1 + countNodes(root.left) + countNodes(root.right);
}
private void augmentTree(AugmentedNode root) {
if (root == null) return;
root.leftCount = countNodes(root.left);
augmentTree(root.left);
augmentTree(root.right);
}
private AugmentedNode kthSmallestAugmented(AugmentedNode root, int k) {
if (root == null) return null;
int leftCount = root.leftCount;
if (k == leftCount + 1) {
return root;
} else if (k <= leftCount) {
return kthSmallestAugmented(root.left, k);
} else {
return kthSmallestAugmented(root.right, k - leftCount - 1);
}
}
public int kthLargestAugmented(AugmentedNode root, int k, int n) {
AugmentedNode node = kthSmallestAugmented(root, n - k + 1);
return node != null ? node.val : -1;
}
}Complexity Analysis
- Time Complexity: O(h) per query after O(n) preprocessing
- Space Complexity: O(n) for augmented data
Key Takeaways
- Reverse inorder: Right-Root-Left gives descending order
- Early termination: Stop once kth element is found
- Relation to kth smallest: kth largest = (n-k+1)th smallest
- Augmented BST: O(h) queries for multiple kth element queries
- This is similar to LeetCode #230 (kth smallest) with reverse traversal
- Iterative version avoids recursion stack overflow for large trees
- For single query, O(h+k) is optimal; for multiple queries, augment the tree