Binary Search Trees · 20 of 22
Check whether BST contains Dead end
Find a leaf in a sorted tree of positive whole numbers where no new number could ever be hung below it, because both neighbors are already taken.
- Simple way
- time O(n)
room O(n) - Clever way
- time O(n)
room O(h)
The problem, simply
You get a binary search tree (BST) that holds only whole numbers bigger than 0, with no repeats. A leaf (a spot with no children) is a dead end if you can never insert any new number under it.
Under a leaf x you could hang x - 1 on the left or x + 1 on the right, or anything else that still fits the BST rules on the way down. A dead end is a leaf where the only number that fits its spot is x itself. Say true if the tree has a dead end.
A story to remember it
Picture it
Each note is the range of numbers that could ever land in that spot. Leaf 9 has range [9, 9]: only 9 itself fits, since 8 and 10 are taken. Leaf 2 still has room from 1 to 6.
- answer
Examples
Dead end in the middle
- In
insert 8, 7, 10, 2, 9, 13- Out
true
Leaf 9: 8 and 10 are both in the tree, so nothing can go under 9.
Dead end at 1
- In
insert 8, 5, 9, 2, 7, 1- Out
true
Leaf 1: 0 is not allowed and 2 is taken. 1 is stuck.
No dead end
- In
insert 8, 4, 12, 2, 6, 10, 14- Out
false
Every leaf has a free neighbor: 2 has 1 and 3, 6 has 5 and 7, 10 has 9 and 11, 14 has 13 and 15.
Only the top
- In
[1]- Out
false
1 is a leaf, but 2 is free on the right. Room left.
Way 1: the simple way
Write down every number in a set, and also write down 0 (because 0 is not allowed, it acts as "taken"). Then look at every leaf x: if both x - 1 and x + 1 are in the set, it is a dead end.
Why this works: for a leaf x, the closest taken numbers on each side are on its road from the top. If x - 1 and x + 1 are both taken, the leaf's range is only x.
import java.util.*;
class Solution {
public boolean isDeadEnd(TreeNode root) {
Set<Integer> taken = new HashSet<>();
Set<Integer> leaves = new HashSet<>();
taken.add(0); // 0 is not allowed, so treat it as taken
collect(root, taken, leaves);
for (int x : leaves) {
if (taken.contains(x - 1) && taken.contains(x + 1)) return true;
}
return false;
}
private void collect(TreeNode node, Set<Integer> taken, Set<Integer> leaves) {
if (node == null) return;
taken.add(node.val);
if (node.left == null && node.right == null) leaves.add(node.val);
collect(node.left, taken, leaves);
collect(node.right, taken, leaves);
}
}How long it takes: every spot once, plus one check per leaf, O(n). Extra room: the two sets, O(n).
Way 2: the clever way
Do not store anything. Carry the range of allowed numbers down the tree, like the BST check.
- The top gets
[1, infinity]. - Going left from
x, the high end becomesx - 1. - Going right from
x, the low end becomesx + 1. - At a leaf, if
low == high, only the leaf itself fits there. Dead end.
Ranges shrink until one is a single number
01 / 06
The top, 8, gets every positive number: [1, inf].
- low
- 1
- high
- inf
- looking now
- checking
- seen
- done
- answer
- path
- ignored
class Solution {
public boolean isDeadEnd(TreeNode root) {
return check(root, 1, Integer.MAX_VALUE);
}
// low and high: the numbers that could still land in this spot
private boolean check(TreeNode node, int low, int high) {
if (node == null) return false;
if (node.left == null && node.right == null) return low == high;
return check(node.left, low, node.val - 1)
|| check(node.right, node.val + 1, high);
}
}How long it takes: every spot once in the worst case, O(n). Extra room: only the recursion, O(h).
Watch out for
- Checking
x - 1andx + 1against the leaf's parent only. The taken neighbor can be far up the road, like 8 for leaf 9. - If the problem allowed 0 or negative numbers, the left end would never block. Ask what the smallest allowed number is.
- Returning at the first leaf. Use
||so the walk keeps going until a dead end is found.
What interviewers ask next
- Return every dead end, not just whether one exists. Collect the leaves where
low == highinto a list. - Count how many numbers can still be inserted under each leaf. It is
high - low, the size of the range minus the leaf itself. - Can a spot that is not a leaf be "full"? Yes, if its range has no room on one side, but then it still has a child. The question only asks about leaves.
- How does this relate to validating a BST? Same idea: pass a window down and tighten it, with
- 1and+ 1because the numbers are whole and distinct.
Remember this
Grown-up words: the stretch of house numbers is the range or bounds, carrying it down is depth first search with bounds, a spot with no children is a leaf node, and treating 0 as taken is a sentinel value.