Turn a Sorted List Into a Balanced Search Tree
Solve this ProblemYou are given an array of integers sorted in strictly increasing order. Build a height-balanced binary search tree that contains exactly these values and return its root. To make the result unique, always choose the middle element of a range as its root (when the range has an even number of elements, the left one of the two middle elements), and build the left and right subtrees from the elements before and after it.
Copying sub-arrays at every step is easy but wasteful; passing index ranges builds the same tree with no copying.
Test Case 1:
Test Case 2:
Test Case 3:
Constraints
- ◆
0 ≤ nums.length ≤ 100; nums is sorted in strictly increasing order; −1000 ≤ nums[i] ≤ 1000 - ◆
Build a binary search tree that contains exactly these values and is height-balanced (at every node the two subtree heights differ by at most 1) - ◆
To make the answer unique: the root of any range of values is its MIDDLE element, and when the range has an even number of elements the LEFT of the two middle elements is used (index (lo + hi) / 2, rounded down) - ◆
Return the root of the tree (checked as a level-order list); an empty list gives the empty tree
Try the Dry Run
Don't just read the solution — watch it execute, one step at a time.
Approach & Solutions
Brute Force — Copy the Left and Right Parts at Every Level
BruteTake the middle element as the root (the left one of two for an even length), then build the left subtree from a COPY of the elements before it and the right subtree from a COPY of the elements after it, recursing on the copies. Halving at every step keeps the tree balanced and the ordering makes it a valid search tree. It is correct, but every level copies all remaining elements: O(n) work per level over log n levels, i.e. O(n log n) time (and extra memory for the copies).
O(n log n)O(n)1class Solution {
2 public TreeNode balancedFromSorted(int[] nums) {
3 if (nums.length == 0) return null;
4 int mid = (nums.length - 1) / 2;
5 TreeNode root = new TreeNode(nums[mid]);
6 root.left = balancedFromSorted(Arrays.copyOfRange(nums, 0, mid));
7 root.right = balancedFromSorted(Arrays.copyOfRange(nums, mid + 1, nums.length));
8 return root;
9 }
10}Optimal — Recurse on Index Ranges Instead of Copies
OptimalThe same divide-and-conquer, but pass the range [lo, hi] of the ORIGINAL array instead of making copies: if lo > hi the range is empty (no node); otherwise the root is nums[mid] with mid = (lo + hi) / 2, the left subtree is built from [lo, mid − 1] and the right subtree from [mid + 1, hi]. Each element becomes a node exactly once and no array is copied: O(n) time, and the recursion is only about log n deep, so the extra space (besides the tree itself) is O(log n).
O(n)O(log n)1class Solution {
2 public TreeNode balancedFromSorted(int[] nums) {
3 return build(nums, 0, nums.length - 1);
4 }
5
6 private TreeNode build(int[] nums, int lo, int hi) {
7 if (lo > hi) return null;
8 int mid = (lo + hi) / 2;
9 TreeNode root = new TreeNode(nums[mid]);
10 root.left = build(nums, lo, mid - 1);
11 root.right = build(nums, mid + 1, hi);
12 return root;
13 }
14}