Binary Search Trees · 10 of 22
Convert a normal BST into a Balanced BST
Turn a lopsided sorted tree into a bushy one with the same numbers, by putting the middle number on top again and again, or by folding a stick in half.
- Simple way
- time O(n)
room O(n) - Clever way
- time O(n)
room O(1)
The problem, simply
You get a binary search tree (BST) that leans badly to one side. It might even be a long stick. Give back a BST with the same numbers that is balanced: at every spot, the heights of the left side and the right side differ by at most 1.
Why it matters: searching a BST costs its height. A stick of a million numbers is a million steps tall. A balanced tree of a million numbers is only about 20 steps tall.
A story to remember it
Picture it
The same seven numbers. Left: a lopsided BST that is 5 rows tall. Right: a balanced BST that is only 3 rows tall.
- done
- rejected
Examples
A lopsided tree
- In
insert 3, 2, 1, 4, 5, 6, 7- Out
[4, 2, 6, 1, 3, 5, 7]
Sorted order is 1 to 7. The middle, 4, goes on top. 2 and 6 are the middles of each half.
A stick of six
- In
[1, null, 2, null, 3, null, 4, null, 5, null, 6]- Out
any 3-row BST, for example [3, 1, 5, null, 2, 4, 6]
With an even count there are two middles. Way 1 below picks 3 and gives this tree. Way 2 gives [4, 2, 6, 1, 3, 5]. Both are balanced, and interviewers accept any balanced answer.
Already balanced
- In
[2, 1, 3]- Out
[2, 1, 3]
Nothing to fix, and both ways give back the same tree.
One spot or none
- In
[5] or []- Out
[5] or []
Trivially balanced.
Way 1: the simple way
Lay the toys out in order, then hang the middle one first.
- Read the tree left, me, right. In a BST that gives the spots in sorted order. Keep the spots themselves in a list, so no new spots are made.
build(lo, hi): iflo > hi, returnnull. Otherwise take the middle spotmid, give itbuild(lo, mid - 1)as its left side andbuild(mid + 1, hi)as its right side, and return it.
The middle hangs on top, halves hang below
01 / 06
Read the lopsided tree left, me, right. The spots come out sorted: 1 to 7.
- seen
- done
- answer
- just added
import java.util.*;
class Solution {
public TreeNode balanceBST(TreeNode root) {
List<TreeNode> spots = new ArrayList<>();
inorder(root, spots); // the spots in sorted order
return build(spots, 0, spots.size() - 1);
}
private void inorder(TreeNode node, List<TreeNode> spots) {
if (node == null) return;
inorder(node.left, spots);
spots.add(node);
inorder(node.right, spots);
}
private TreeNode build(List<TreeNode> spots, int lo, int hi) {
if (lo > hi) return null;
int mid = (lo + hi) / 2; // the middle toy hangs on top
TreeNode node = spots.get(mid);
node.left = build(spots, lo, mid - 1);
node.right = build(spots, mid + 1, hi);
return node;
}
}How long it takes: one read and one build, each touching every spot once, O(n). Extra room: the list of n spots, O(n). This is the answer most interviewers expect.
Way 2: the clever way
If you may not use a list, do it with only twists, called rotations. A rotation lifts a child above its parent and keeps the BST order. This is the Day, Stout and Warren method.
- Make a stick. Walk down the right edge from a dummy spot above the top. Whenever a spot has a left child, rotate that child up. When there is no left child, step right. At the end every spot hangs to the right, in sorted order. Count them:
n. - Fold the stick. Let
fullbe the biggest number of the form2^k - 1that is at mostn. First rotate leftn - fulltimes, at every second spot, so the extra spots drop down to be the bottom row. - Then for
m = full / 2,full / 4, ... down to 1: walk down the right edge and rotate every second spot left,mtimes. Each round folds the stick in half and adds one row.
Straighten into a stick, then fold it in half twice
01 / 08
Start. 3 has a left child, 2. Rotate right: 2 goes up and 3 becomes its right child.
- phase
- make a stick
- looking now
- checking
- done
- answer
- just added
class Solution {
public TreeNode balanceBST(TreeNode root) {
TreeNode dummy = new TreeNode(0); // a hook above the top
dummy.right = root;
int n = makeStick(dummy);
int full = Integer.highestOneBit(n + 1) - 1; // biggest 2^k - 1 that is <= n
fold(dummy, n - full); // drop the extra spots to the bottom row
for (int m = full / 2; m > 0; m /= 2) fold(dummy, m);
return dummy.right;
}
// rotate right until nothing has a left child; returns the number of spots
private int makeStick(TreeNode dummy) {
int n = 0;
TreeNode tail = dummy, rest = dummy.right;
while (rest != null) {
if (rest.left != null) {
TreeNode up = rest.left; // the left child goes up
rest.left = up.right;
up.right = rest;
tail.right = up;
rest = up;
} else {
n++;
tail = rest;
rest = rest.right;
}
}
return n;
}
// walk the right edge and rotate every second spot left, m times
private void fold(TreeNode dummy, int m) {
TreeNode scan = dummy;
for (int i = 0; i < m; i++) {
TreeNode down = scan.right; // this spot goes down
scan.right = down.right; // its right child comes up
scan = scan.right;
down.right = scan.left;
scan.left = down;
}
}
}How long it takes: making the stick uses at most n rotations, and the folds use n/2 + n/4 + ..., less than n. So O(n). Extra room: a few fingers and a dummy, O(1).
Watch out for
- Forgetting to clear old links. In Way 1,
buildoverwrites bothleftandrightof every spot, so old links never survive. If you skip thenullreturns, leaves keep their old children. - Using
(lo + hi) / 2with huge indices can overflow.lo + (hi - lo) / 2is safe. - "Balanced" does not mean "perfect". With 6 spots one leaf is missing, and that is fine.
What interviewers ask next
- Build a balanced BST from a sorted array (LeetCode 108). It is the
buildhalf of Way 1. - Build one from a sorted linked list without copying to an array (LeetCode 109). Count the list, then build the left half first while a finger walks the list in order.
O(n)time,O(log n)room. - How do real libraries stay balanced? They rotate a little after every insert and delete (AVL trees, red black trees), so they never need a full rebuild. Java's
TreeMapis a red black tree. - Scapegoat trees do the opposite: let the tree go out of shape, and when one part gets too lopsided, rebuild just that part with Way 1. That is still
O(log n)per operation on average.
Remember this
Grown-up words: the even mobile is a height-balanced BST, laying the toys out in order is an inorder traversal, hanging the middle first is divide and conquer, a twist that lifts a child is a tree rotation, the stick is a vine, and the fold method is the Day Stout Warren (DSW) algorithm.