Convert Sorted Array to Height-Balanced BST
Imagine you have a sorted list of book IDs and want to organize them in a way that allows quick search and insertion. Creating a balanced binary search tree from this sorted list ensures efficient operations.
Given an integer array nums where the elements are sorted in ascending order, convert it to a height-balanced binary search tree. A height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differs by more than one.
1 ≤ nums.length ≤ 10^5-10^4 ≤ nums[i] ≤ 10^4nums is sorted in ascending order"nums = [-10, -3, 0, 5, 9]"[0, -3, 9, -10, null, 5]Choosing 0 as root splits array into left [-10, -3] and right [5, 9]. Recursively building subtrees results in a balanced BST. Note: This output is a level order traversal with nulls for missing nodes. In test cases, inorder traversal arrays are used to verify correctness.
- Single element array → tree with one node
- Two elements array → root and one child
- All elements are the same → balanced tree with duplicates allowed
- Large array with 10^5 elements → performance and stack depth considerations
Creates skewed tree, leading to O(n^2) time and unbalanced BST
✅ Use divide and conquer to pick middle element as root
Stack overflow or infinite loop
✅ Calculate mid as (left + right) // 2 or left + (right - left) // 2
Recursion never ends or returns wrong subtree
✅ Return null when left > right
Extra O(n) space and time overhead per call, inefficient for large inputs
✅ Use indices to pass subarray boundaries instead of slicing
Incorrect tree structure, failing balance or BST property
✅ Carefully assign left subtree to left..mid-1 and right subtree to mid+1..right
Intuition
Insert each element from the sorted array into the BST in order. Since the array is sorted, inserting sequentially creates a skewed tree.
Algorithm
- Initialize an empty BST.
- Iterate over each element in the sorted array.
- Insert the current element into the BST using standard BST insertion.
- Return the root of the BST after all insertions.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def insert_into_bst(root, val):
if not root:
return TreeNode(val)
if val < root.val:
root.left = insert_into_bst(root.left, val)
else:
root.right = insert_into_bst(root.right, val)
return root
def sorted_array_to_bst(nums):
root = None
for num in nums:
root = insert_into_bst(root, num)
return root
# Driver code to test
if __name__ == '__main__':
nums = [-10, -3, 0, 5, 9]
root = sorted_array_to_bst(nums)
# Simple inorder traversal to print sorted values
def inorder(node):
return inorder(node.left) + [node.val] + inorder(node.right) if node else []
print(inorder(root))class TreeNode:Defines the structure of a BST node with value and left/right childrendef insert_into_bst(root, val):Defines recursive insertion function for BSTif not root:Base case: insert new node when reaching null positionif val < root.val:Decide to go left or right based on BST propertyroot.left = insert_into_bst(root.left, val)Recursively insert in left subtreefor num in nums:Iterate over all elements to insert sequentiallyroot = insert_into_bst(root, num)Update root after each insertionclass TreeNode {
int val;
TreeNode left, right;
TreeNode(int val) { this.val = val; }
}
public class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
if (root == null) return new TreeNode(val);
if (val < root.val) root.left = insertIntoBST(root.left, val);
else root.right = insertIntoBST(root.right, val);
return root;
}
public TreeNode sortedArrayToBST(int[] nums) {
TreeNode root = null;
for (int num : nums) {
root = insertIntoBST(root, num);
}
return root;
}
public static void inorder(TreeNode root) {
if (root == null) return;
inorder(root.left);
System.out.print(root.val + " ");
inorder(root.right);
}
public static void main(String[] args) {
Solution sol = new Solution();
int[] nums = {-10, -3, 0, 5, 9};
TreeNode root = sol.sortedArrayToBST(nums);
inorder(root);
}
}class TreeNode {Defines BST node structure with value and childrenpublic TreeNode insertIntoBST(TreeNode root, int val) {Recursive insertion method for BSTif (root == null) return new TreeNode(val);Base case: create new node when null reachedif (val < root.val) root.left = insertIntoBST(root.left, val);Insert into left subtree if smallerfor (int num : nums) {Iterate over all elements to insert sequentiallyroot = insertIntoBST(root, num);Update root after each insertionpublic static void main(String[] args) {Driver code entry point#include <iostream>
#include <vector>
using namespace std;
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
TreeNode* insertIntoBST(TreeNode* root, int val) {
if (!root) return new TreeNode(val);
if (val < root->val) root->left = insertIntoBST(root->left, val);
else root->right = insertIntoBST(root->right, val);
return root;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
TreeNode* root = nullptr;
for (int num : nums) {
root = insertIntoBST(root, num);
}
return root;
}
void inorder(TreeNode* root) {
if (!root) return;
inorder(root->left);
cout << root->val << " ";
inorder(root->right);
}
int main() {
vector<int> nums = {-10, -3, 0, 5, 9};
TreeNode* root = sortedArrayToBST(nums);
inorder(root);
cout << endl;
return 0;
}struct TreeNode {Defines BST node with value and pointers to childrenTreeNode* insertIntoBST(TreeNode* root, int val) {Recursive insertion function for BSTif (!root) return new TreeNode(val);Create new node when null reachedif (val < root->val) root->left = insertIntoBST(root->left, val);Insert into left subtree if smallerfor (int num : nums) {Iterate over all elements to insert sequentiallyroot = insertIntoBST(root, num);Update root after each insertionint main() {Driver code entry pointclass TreeNode {
constructor(val=0, left=null, right=null) {
this.val = val;
this.left = left;
this.right = right;
}
}
function insertIntoBST(root, val) {
if (!root) return new TreeNode(val);
if (val < root.val) root.left = insertIntoBST(root.left, val);
else root.right = insertIntoBST(root.right, val);
return root;
}
function sortedArrayToBST(nums) {
let root = null;
for (const num of nums) {
root = insertIntoBST(root, num);
}
return root;
}
// Driver code
const nums = [-10, -3, 0, 5, 9];
const root = sortedArrayToBST(nums);
function inorder(node) {
if (!node) return [];
return [...inorder(node.left), node.val, ...inorder(node.right)];
}
console.log(inorder(root));class TreeNode {Defines BST node with value and left/right childrenfunction insertIntoBST(root, val) {Recursive insertion function for BSTif (!root) return new TreeNode(val);Create new node when null reachedif (val < root.val) root.left = insertIntoBST(root.left, val);Insert into left subtree if smallerfor (const num of nums) {Iterate over all elements to insert sequentiallyroot = insertIntoBST(root, num);Update root after each insertionconsole.log(inorder(root));Print inorder traversal to verify BSTO(n^2)O(n)Each insertion takes O(h) time, where h is tree height. Since tree becomes skewed, h can be O(n), so total O(n^2).
This approach works but is too slow for large inputs and produces unbalanced trees, so better methods are preferred.
Intuition
Pick the middle element of the current subarray as root, recursively build left subtree from left half and right subtree from right half.
Algorithm
- Define a recursive function that takes left and right indices of the current subarray.
- If left > right, return null (base case).
- Find mid = (left + right) // 2, create a node with nums[mid].
- Recursively build left subtree from left to mid-1 and right subtree from mid+1 to right.
- Return the node.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def helper(nums, left, right):
if left > right:
return None
mid = (left + right) // 2
root = TreeNode(nums[mid])
root.left = helper(nums, left, mid - 1)
root.right = helper(nums, mid + 1, right)
return root
def sorted_array_to_bst(nums):
return helper(nums, 0, len(nums) - 1)
# Driver code
if __name__ == '__main__':
nums = [-10, -3, 0, 5, 9]
root = sorted_array_to_bst(nums)
def inorder(node):
return inorder(node.left) + [node.val] + inorder(node.right) if node else []
print(inorder(root))class TreeNode:Defines the BST node structure with value and childrendef helper(nums, left, right):Recursive helper to build BST from subarrayif left > right:Base case: no elements to processmid = (left + right) // 2Pick middle element to maintain balanceroot = TreeNode(nums[mid])Create node with middle element as rootroot.left = helper(nums, left, mid - 1)Build left subtree recursivelyroot.right = helper(nums, mid + 1, right)Build right subtree recursivelyreturn rootReturn constructed subtree rootclass TreeNode {
int val;
TreeNode left, right;
TreeNode(int val) { this.val = val; }
}
public class Solution {
public TreeNode helper(int[] nums, int left, int right) {
if (left > right) return null;
int mid = left + (right - left) / 2;
TreeNode root = new TreeNode(nums[mid]);
root.left = helper(nums, left, mid - 1);
root.right = helper(nums, mid + 1, right);
return root;
}
public TreeNode sortedArrayToBST(int[] nums) {
return helper(nums, 0, nums.length - 1);
}
public static void inorder(TreeNode root) {
if (root == null) return;
inorder(root.left);
System.out.print(root.val + " ");
inorder(root.right);
}
public static void main(String[] args) {
Solution sol = new Solution();
int[] nums = {-10, -3, 0, 5, 9};
TreeNode root = sol.sortedArrayToBST(nums);
inorder(root);
}
}class TreeNode {Defines BST node structurepublic TreeNode helper(int[] nums, int left, int right) {Recursive helper to build BST from subarrayif (left > right) return null;Base case: no elements leftint mid = left + (right - left) / 2;Calculate middle index safelyTreeNode root = new TreeNode(nums[mid]);Create node with middle element as rootroot.left = helper(nums, left, mid - 1);Build left subtree recursivelyroot.right = helper(nums, mid + 1, right);Build right subtree recursivelyreturn root;Return constructed subtree root#include <iostream>
#include <vector>
using namespace std;
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
TreeNode* helper(const vector<int>& nums, int left, int right) {
if (left > right) return nullptr;
int mid = left + (right - left) / 2;
TreeNode* root = new TreeNode(nums[mid]);
root->left = helper(nums, left, mid - 1);
root->right = helper(nums, mid + 1, right);
return root;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
return helper(nums, 0, nums.size() - 1);
}
void inorder(TreeNode* root) {
if (!root) return;
inorder(root->left);
cout << root->val << " ";
inorder(root->right);
}
int main() {
vector<int> nums = {-10, -3, 0, 5, 9};
TreeNode* root = sortedArrayToBST(nums);
inorder(root);
cout << endl;
return 0;
}struct TreeNode {Defines BST node structureTreeNode* helper(const vector<int>& nums, int left, int right) {Recursive helper to build BST from subarrayif (left > right) return nullptr;Base case: no elements leftint mid = left + (right - left) / 2;Calculate middle index safelyTreeNode* root = new TreeNode(nums[mid]);Create node with middle element as rootroot->left = helper(nums, left, mid - 1);Build left subtree recursivelyroot->right = helper(nums, mid + 1, right);Build right subtree recursivelyreturn root;Return constructed subtree rootclass TreeNode {
constructor(val=0, left=null, right=null) {
this.val = val;
this.left = left;
this.right = right;
}
}
function helper(nums, left, right) {
if (left > right) return null;
const mid = Math.floor((left + right) / 2);
const root = new TreeNode(nums[mid]);
root.left = helper(nums, left, mid - 1);
root.right = helper(nums, mid + 1, right);
return root;
}
function sortedArrayToBST(nums) {
return helper(nums, 0, nums.length - 1);
}
// Driver code
const nums = [-10, -3, 0, 5, 9];
const root = sortedArrayToBST(nums);
function inorder(node) {
if (!node) return [];
return [...inorder(node.left), node.val, ...inorder(node.right)];
}
console.log(inorder(root));class TreeNode {Defines BST node structurefunction helper(nums, left, right) {Recursive helper to build BST from subarrayif (left > right) return null;Base case: no elements leftconst mid = Math.floor((left + right) / 2);Calculate middle index safelyconst root = new TreeNode(nums[mid]);Create node with middle element as rootroot.left = helper(nums, left, mid - 1);Build left subtree recursivelyroot.right = helper(nums, mid + 1, right);Build right subtree recursivelyreturn root;Return constructed subtree rootO(n)O(log n)Each element is visited once to create nodes. Recursion stack depth is O(log n) due to balanced splits.
This is the standard and optimal approach for this problem, balancing simplicity and performance.
Intuition
Use recursion to build left subtree of size n/2, then create root from middle element, then build right subtree. This simulates inorder traversal.
Algorithm
- Maintain a global or external index pointer starting at 0.
- Recursively build left subtree from left to mid-1.
- Create root node with nums[mid].
- Increment index pointer.
- Recursively build right subtree from mid+1 to right.
- Return root node.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def __init__(self):
self.index = 0
def helper(self, nums, left, right):
if left > right:
return None
mid = (left + right) // 2
left_child = self.helper(nums, left, mid - 1)
root = TreeNode(nums[mid])
self.index += 1
root.left = left_child
root.right = self.helper(nums, mid + 1, right)
return root
def sorted_array_to_bst(self, nums):
self.index = 0
return self.helper(nums, 0, len(nums) - 1)
# Driver code
if __name__ == '__main__':
nums = [-10, -3, 0, 5, 9]
sol = Solution()
root = sol.sorted_array_to_bst(nums)
def inorder(node):
return inorder(node.left) + [node.val] + inorder(node.right) if node else []
print(inorder(root))class TreeNode:Defines BST node structureclass Solution:Encapsulates index pointer and helper methodself.index = 0Reset index before recursiondef helper(self, nums, left, right):Recursive helper to build BST simulating inorder traversalif left > right:Base case: no elements leftmid = (left + right) // 2Calculate middle indexleft_child = self.helper(nums, left, mid - 1)Build left subtree first to simulate inorderroot = TreeNode(nums[mid])Create root node from middle element to maintain BST propertyself.index += 1Increment index pointer after using elementroot.left = left_childAssign left subtreeroot.right = self.helper(nums, mid + 1, right)Build right subtree after rootreturn rootReturn constructed subtree rootdef sorted_array_to_bst(self, nums):Entry function to start recursionclass TreeNode {
int val;
TreeNode left, right;
TreeNode(int val) { this.val = val; }
}
public class Solution {
int index = 0;
public TreeNode helper(int[] nums, int left, int right) {
if (left > right) return null;
int mid = (left + right) / 2;
TreeNode leftChild = helper(nums, left, mid - 1);
TreeNode root = new TreeNode(nums[mid]);
index++;
root.left = leftChild;
root.right = helper(nums, mid + 1, right);
return root;
}
public TreeNode sortedArrayToBST(int[] nums) {
index = 0;
return helper(nums, 0, nums.length - 1);
}
public static void inorder(TreeNode root) {
if (root == null) return;
inorder(root.left);
System.out.print(root.val + " ");
inorder(root.right);
}
public static void main(String[] args) {
Solution sol = new Solution();
int[] nums = {-10, -3, 0, 5, 9};
TreeNode root = sol.sortedArrayToBST(nums);
inorder(root);
}
}class TreeNode {Defines BST node structureint index = 0;Index pointer to track current elementpublic TreeNode helper(int[] nums, int left, int right) {Recursive helper simulating inorder traversalif (left > right) return null;Base case: no elements leftint mid = (left + right) / 2;Calculate middle indexTreeNode leftChild = helper(nums, left, mid - 1);Build left subtree firstTreeNode root = new TreeNode(nums[mid]);Create root node from middle elementindex++;Increment index after using elementroot.left = leftChild;Assign left subtreeroot.right = helper(nums, mid + 1, right);Build right subtree after rootreturn root;Return constructed subtree rootpublic TreeNode sortedArrayToBST(int[] nums) {Entry function to start recursionindex = 0;Reset index before recursion#include <iostream>
#include <vector>
using namespace std;
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
class Solution {
public:
int index = 0;
TreeNode* helper(const vector<int>& nums, int left, int right) {
if (left > right) return nullptr;
int mid = (left + right) / 2;
TreeNode* leftChild = helper(nums, left, mid - 1);
TreeNode* root = new TreeNode(nums[mid]);
index++;
root->left = leftChild;
root->right = helper(nums, mid + 1, right);
return root;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
index = 0;
return helper(nums, 0, nums.size() - 1);
}
};
void inorder(TreeNode* root) {
if (!root) return;
inorder(root->left);
cout << root->val << " ";
inorder(root->right);
}
int main() {
vector<int> nums = {-10, -3, 0, 5, 9};
Solution sol;
TreeNode* root = sol.sortedArrayToBST(nums);
inorder(root);
cout << endl;
return 0;
}struct TreeNode {Defines BST node structureint index = 0;Index pointer to track current elementTreeNode* helper(const vector<int>& nums, int left, int right) {Recursive helper simulating inorder traversalif (left > right) return nullptr;Base case: no elements leftint mid = (left + right) / 2;Calculate middle indexTreeNode* leftChild = helper(nums, left, mid - 1);Build left subtree firstTreeNode* root = new TreeNode(nums[mid]);Create root node from middle elementindex++;Increment index after using elementroot->left = leftChild;Assign left subtreeroot->right = helper(nums, mid + 1, right);Build right subtree after rootreturn root;Return constructed subtree rootTreeNode* sortedArrayToBST(vector<int>& nums) {Entry function to start recursionindex = 0;Reset index before recursionclass TreeNode {
constructor(val=0, left=null, right=null) {
this.val = val;
this.left = left;
this.right = right;
}
}
class Solution {
constructor() {
this.index = 0;
}
helper(nums, left, right) {
if (left > right) return null;
const mid = Math.floor((left + right) / 2);
const leftChild = this.helper(nums, left, mid - 1);
const root = new TreeNode(nums[mid]);
this.index++;
root.left = leftChild;
root.right = this.helper(nums, mid + 1, right);
return root;
}
sortedArrayToBST(nums) {
this.index = 0;
return this.helper(nums, 0, nums.length - 1);
}
}
// Driver code
const nums = [-10, -3, 0, 5, 9];
const sol = new Solution();
const root = sol.sortedArrayToBST(nums);
function inorder(node) {
if (!node) return [];
return [...inorder(node.left), node.val, ...inorder(node.right)];
}
console.log(inorder(root));class TreeNode {Defines BST node structureconstructor() {Initialize index pointerthis.index = 0;Reset index before recursionhelper(nums, left, right) {Recursive helper simulating inorder traversalif (left > right) return null;Base case: no elements leftconst mid = Math.floor((left + right) / 2);Calculate middle indexconst leftChild = this.helper(nums, left, mid - 1);Build left subtree firstconst root = new TreeNode(nums[mid]);Create root node from middle elementthis.index++;Increment index after using elementroot.left = leftChild;Assign left subtreeroot.right = this.helper(nums, mid + 1, right);Build right subtree after rootreturn root;Return constructed subtree rootO(n)O(log n)Each element is processed once. Recursion stack depth is O(log n) due to balanced tree construction.
This approach is optimal in time and space, especially for large inputs, and avoids extra array slicing.
| Approach | Time | Space | Stack Risk | Reconstruct | Use In Interview |
|---|---|---|---|---|---|
| 1. Brute Force (Insert One by One) | O(n^2) | O(n) | Yes (deep recursion if skewed) | Yes | Mention only - never code |
| 2. Divide and Conquer Recursion | O(n) | O(log n) | No (balanced recursion depth) | Yes | Code this approach in most interviews |
| 3. Inorder Simulation with Index Pointer | O(n) | O(log n) | No | Yes | Use for large inputs or when avoiding slicing |
How to Present
Clarify the problem and constraints.Describe the brute force approach of inserting elements one by one and its drawbacks.Introduce the divide and conquer recursive approach using the middle element.Explain the optimal inorder simulation approach to avoid extra space.Write clean code and test with examples.
Time Allocation
What the Interviewer Tests
The interviewer tests your understanding of BST properties, recursion, balanced tree construction, and ability to optimize naive solutions.
Common Follow-ups
- What if the input is a linked list instead of an array? → Use slow/fast pointers to find middle.
- How to validate if a tree is height-balanced? → Check height difference recursively.
When to Use
1) Input is sorted array or list, 2) Need to build BST, 3) Balanced tree required, 4) Recursive divide and conquer fits
