Which Stored Value Comes Right Before a Key
Solve this ProblemYou are given the root of a binary search tree with distinct values and an integer key (the key need not be in the tree). Return the value that comes immediately before key in the ascending order of the tree's values — the largest value strictly smaller than key — or -1 if no value is smaller.
A list of all values makes this a simple scan. Walking down the tree once and remembering the last node where you turned right finds it directly.
Test Case 1:
Test Case 2:
Test Case 3:
Constraints
- ◆
0 ≤ number of nodes ≤ 100; all node values are distinct, 0 ≤ node.val ≤ 1000 - ◆
The tree is a binary search tree (left subtree smaller, right subtree larger at every node), given by its root node - ◆
key is any integer between 0 and 1000 (it does not have to be in the tree) - ◆
Return the value that comes immediately before key when the tree's values are listed in ascending order — that is, the largest value that is STRICTLY smaller than key. If there is none, return -1
Try the Dry Run
Don't just read the solution — watch it execute, one step at a time.
Approach & Solutions
Brute Force — List All Values, Keep the Last One Below the Key
BruteAn inorder walk gives the values in ascending order. Collect them in a list and scan it, remembering the last value that is strictly smaller than the key; because the list ascends, that last value is the one that comes right before the key. If nothing is smaller, the answer stays -1. It walks all n nodes and stores all n values: O(n) time and O(n) space.
O(n)O(n)1class Solution {
2 public int predecessorOf(TreeNode root, int key) {
3 List<Integer> vals = new ArrayList<>();
4 inorder(root, vals);
5 int best = -1;
6 for (int v : vals) {
7 if (v < key) best = v;
8 }
9 return best;
10 }
11
12 private void inorder(TreeNode node, List<Integer> vals) {
13 if (node == null) return;
14 inorder(node.left, vals);
15 vals.add(node.val);
16 inorder(node.right, vals);
17 }
18}Optimal — Descend Once, Remembering the Last Node Where We Turned Right
OptimalWalk down from the root. If the current node's value is smaller than the key, it is a candidate for "the value just before the key" — remember it — and a larger candidate (still below the key) could only be in its RIGHT subtree, so go right. If the current node's value is not smaller than the key, neither it nor anything on its right can qualify, so go LEFT. When the path ends, the last remembered candidate is the predecessor (or -1). This handles both cases at once: the rightmost node of the key's left subtree, or the nearest ancestor from which the path turned right. O(h) time, O(1) space.
O(h)O(1)1class Solution {
2 public int predecessorOf(TreeNode root, int key) {
3 int best = -1;
4 TreeNode cur = root;
5 while (cur != null) {
6 if (cur.val < key) {
7 best = cur.val;
8 cur = cur.right;
9 } else {
10 cur = cur.left;
11 }
12 }
13 return best;
14 }
15}