Binary Search Trees · 22 of 22
Flatten BST to sorted list
Rewire a sorted tree into one straight sorted chain, reusing its own spots, by visiting them in order and hooking each one after the last.
- 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). Turn it into a sorted chain using the same spots: every spot's left must become null, and its right must point to the next bigger number. Give back the smallest spot, which is the start of the chain.
Do not create new spots. Only change arrows.
A story to remember it
Picture it
The tree and the chain it becomes. Same six spots. In the chain every left arrow is gone and every right arrow points to the next bigger number.
Examples
A normal tree
- In
[5, 3, 7, 1, 4, null, 10]- Out
1 > 3 > 4 > 5 > 7 > 10
The chain is the left side, me, right side order.
A stick going left
- In
[3, 2, null, 1]- Out
1 > 2 > 3
The bottom spot becomes the start. The old top becomes the end.
Already a chain
- In
[1, null, 2, null, 3]- Out
1 > 2 > 3
Nothing changes. Every left is already null.
One spot or none
- In
[7] or []- Out
7 or null
A single spot is a chain of one. An empty tree gives null.
Way 1: the simple way
Write the spots down in order, then hook them up.
- Visit left side, me, right side and add each spot to a list.
- For each spot in the list: set
left = nullandright= the next spot in the list (nullfor the last one). - Return the first spot.
import java.util.*;
class Solution {
public TreeNode flatten(TreeNode root) {
List<TreeNode> order = new ArrayList<>();
inorder(root, order);
for (int i = 0; i < order.size(); i++) {
TreeNode node = order.get(i);
node.left = null;
node.right = (i + 1 < order.size()) ? order.get(i + 1) : null;
}
return order.isEmpty() ? null : order.get(0);
}
private void inorder(TreeNode node, List<TreeNode> order) {
if (node == null) return;
inorder(node.left, order);
order.add(node);
inorder(node.right, order);
}
}How long it takes: two passes, O(n). Extra room: the list of all spots, O(n).
Way 2: the clever way
Hook as you go, with one finger on the end of the chain.
- Make a dummy spot. The finger
tailstarts on it. The chain will hang fromdummy.right. - Visit the spots left side, me, right side.
- At each spot:
tail.right = spot,spot.left = null, thentail = spot. - Return
dummy.right.
Why it is safe to cut spot.left: when we reach a spot, its whole left side has already been visited and hooked into the chain. Its right is still read by the recursion before anyone overwrites it, because a spot's right is only changed when the next spot is hooked, and the next spot is inside that right side or above it.
Each spot joins the end of the line
01 / 07
Start with a dummy at the front of an empty line. tail is on the dummy. Walk down the left side to the smallest spot.
- looking now
- done
- answer
- path
- just added
class Solution {
private TreeNode tail; // the last spot in the line
public TreeNode flatten(TreeNode root) {
TreeNode dummy = new TreeNode(0);
tail = dummy;
walk(root);
return dummy.right;
}
private void walk(TreeNode node) {
if (node == null) return;
walk(node.left); // everything smaller joins first
node.left = null; // safe: the left side is already in line
tail.right = node; // join the end of the line
tail = node;
walk(node.right); // then everything bigger
}
}How long it takes: every spot once, O(n). Extra room: no list, only the recursion, O(h). The last spot's right is already null (it was the biggest, with no right side), so the line ends properly.
Watch out for
- Forgetting
node.left = null. The chain looks right when you followright, but leftover left arrows make it a tree with loops. - Returning the old top instead of
dummy.right. The top is in the middle of the line. - Keeping
tailas a parameter. Each call needs to see the latest end of the line, so it must be a field.
What interviewers ask next
- Make a doubly linked chain, also circular (LeetCode 426). Same walk, but also set
node.left = tail, and at the end hook the last spot to the first. - Flatten a plain binary tree into a chain in preorder (LeetCode 114). Different order: for each spot, splice its left side between it and its right side.
- Do it with
O(1)room. Use Morris (temporary ropes), or the reverse trick: walk right side, me, left side and push each spot onto the front of the chain. - Turn the chain back into a balanced BST. Count it, then build the left half first while a finger walks the chain.
O(n).
Remember this
Grown-up words: the conga line is a singly linked list made of tree nodes, left, me, right is an inorder traversal, the finger is a tail (or prev) pointer, the dummy spot is a sentinel node, and doing it without new spots is an in-place conversion.