Hello! Welcome to the final lesson in our module on Binary Search Trees.
In our last session, we explored how to find the Lowest Common Ancestor (LCA) by leveraging the BST's ordering property to efficiently navigate the tree. Today, we'll tackle another classic problem that sits at the intersection of arrays and trees: constructing a height-balanced BST from a sorted array.
This is a very common interview question (famously LeetCode 108) because it tests your understanding of what makes a BST balanced, your ability to work with recursion, and your skill in applying a divide-and-conquer strategy. By the end of this lesson, you will be able to implement an efficient algorithm to solve this problem.

The Core Idea: Divide and Conquer
First, let's consider what not to do. If we take the sorted array and insert the elements one by one into a BST, what would the resulting tree look like? Since each new element is larger than the previous one, every insertion would go to the right. The result would be a skewed tree that behaves like a linked list, with height. This defeats the purpose of a BST, as operations like search would degrade to time complexity.
The key to building a height-balanced tree is to ensure that for any node, the number of nodes in its left subtree is roughly equal to the number of nodes in its right subtree.
Given that our input array is sorted, how can we achieve this? The most intuitive way is to select the middle element of the array to be the root of the tree.
Why does this work?
- All elements to the left of the middle element are smaller, so they naturally belong in the left subtree.
- All elements to the right of the middle element are larger, so they naturally belong in the right subtree.
This single choice partitions the problem perfectly. We are left with two smaller sorted subarrays, and we can apply the exact same logic to them recursively to build the left and right subtrees. This is a classic divide-and-conquer approach.
Let's watch a video that breaks down this strategy visually.
Convert Sorted Array to Binary Search Tree - Leetcode 108 - Python
This video from NeetCode provides an excellent walkthrough of the problem. Pay close attention to how choosing the middle element as the root naturally leads to a recursive solution and a balanced tree.
Watch from the beginning to 06:33. This portion introduces the problem, explains the core 'middle element' strategy, and provides a step-by-step visual trace of the recursive construction.
The Recursive Algorithm
As the video illustrates, the algorithm can be implemented elegantly with a recursive helper function. To avoid the inefficiency of creating new array slices in each recursive call (which would lead to an solution), we pass pointers or indices (left and right) to define the current subarray we are working on.
The algorithm for a helper function, say build(left, right), looks like this:
-
Base Case: If the
leftindex is greater than therightindex, it means the current subarray is empty. There are no nodes to create, so we returnNone. This is the condition that stops the recursion. -
Find the Middle: Calculate the middle index of the current subarray:
mid = (left + right) // 2. -
Create the Root: Create a new
TreeNodeusing the element at the middle index,nums[mid]. This node will be the root of the (sub)tree for the current range. -
Recursive Step:
- Recursively build the left subtree by calling
build(left, mid - 1). The result of this call becomes theleftchild of the root node we just created. - Recursively build the right subtree by calling
build(mid + 1, right). The result of this call becomes therightchild.
- Recursively build the left subtree by calling
-
Return: Return the
rootnode created in step 3.
The initial call to this function would be build(0, len(nums) - 1) to start the process with the entire array.
Now, let's see this algorithm translated into Python code.
Convert Sorted Array to Binary Search Tree - Leetcode 108 - Python
Continuing with the NeetCode video, let's watch the coding part. Notice how the Python code is a direct translation of the recursive logic we just outlined.
Watch from 06:33 to 09:15. The video explains the helper function, the base case, and the recursive calls.
Here is the final Python code for your reference. This is a standard pattern you should be comfortable with for interviews.
# Definition for a binary tree node.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution:
def sortedArrayToBST(self, nums: list[int]) -> TreeNode:
def build(left, right):
# Base case: If the pointers cross, the subarray is empty.
if left > right:
return None
# Find the middle element to make it the root.
mid = (left + right) // 2
root = TreeNode(nums[mid])
# Recursively build the left and right subtrees.
root.left = build(left, mid - 1)
root.right = build(mid + 1, right)
return root
# Start the recursion with the entire array.
return build(0, len(nums) - 1)
Test your understanding!
Given the sorted array nums = [1, 2, 3, 4, 5, 6, 7], trace the first two levels of the recursive algorithm.
- What is the value of the root of the entire tree?
- What are the
leftandrightindex ranges for the two recursive calls made from the root? - What are the root nodes of the left and right subtrees?
Show answer
-
Initial call:
build(0, 6).mid = (0 + 6) // 2 = 3. The root node's value isnums[3], which is 4.
-
Recursive calls from the root (node 4):
- Left subtree:
build(0, mid - 1), which isbuild(0, 2). - Right subtree:
build(mid + 1, 6), which isbuild(4, 6).
- Left subtree:
-
Roots of the subtrees:
- For the left subtree (
build(0, 2)):mid = (0 + 2) // 2 = 1. The root isnums[1], which is 2. - For the right subtree (
build(4, 6)):mid = (4 + 6) // 2 = 5. The root isnums[5], which is 6.
- For the left subtree (
The top of the tree looks like this:
4
/ \
2 6
... ...
Complexity Analysis
Understanding the performance of this algorithm is critical.
108. Convert Sorted Array to Binary Search Tree - Complexity
Let's solidify our understanding of the time and space complexity. This article from Algo.Monster provides a concise explanation.
Read the section 'Time and Space Complexity'. Pay attention to the distinction between the space used by the recursion stack and the space for the output tree.
To summarize the complexity:
-
Time Complexity:
We visit each element in the input array exactly once to create a correspondingTreeNode. The work done at each recursive call (finding the middle, creating a node) is constant, . Therefore, the total time is proportional to the number of nodes,N. -
Space Complexity:
The space required is determined by the depth of the recursion call stack. Since our algorithm deliberately constructs a balanced tree, the height of the tree is . Thus, the maximum depth of the recursion stack will be . (Note: The output tree itself requires space, but in complexity analysis, we often focus on the auxiliary space used by the algorithm, which is the call stack in this case).
Common Pitfalls
When implementing this in an interview, be mindful of a few common mistakes.
- Off-by-one errors: The base case
left > rightis crucial for correctly handling inclusive indices. A common error is usingleft >= right, which would fail for subarrays with a single element. - Inefficient array slicing: Slicing the array (e.g.,
nums[:mid]) in each recursive call creates copies and degrades time complexity to and space complexity to . Always use indices to represent subarrays. The article from Algo.Monster you just reviewed discusses this and other pitfalls in its "Common Pitfalls" section, which is a good follow-up read.
Conclusion
Congratulations on completing the Binary Search Trees module! We've covered the core operations, validation, traversal-based problems like finding the k-th smallest element, finding the LCA, and finally, construction.
Key Takeaways from this lesson:
- To construct a height-balanced BST from a sorted array, use a divide-and-conquer strategy.
- The key is to recursively select the middle element of the current subarray as the root. This naturally ensures balance.
- The most efficient implementation uses a recursive helper function with indices to avoid costly array slicing.
- The algorithm is highly efficient, with time complexity and auxiliary space complexity.
In our next module, we will move on to another powerful tree-based data structure: the Heap. We'll see how heaps are used to implement Priority Queues and solve a different class of problems, such as finding the "Top K" elements in a dataset or managing tasks by priority. See you then