We're given a sorted singly linked list and need to build a height-balanced BST from it. This is closely related to converting a sorted array to a BST, with one difference that drives the whole problem: an array can jump to its middle element in O(1), while a linked list has to walk there node by node.
The sorted order of the list is the in-order traversal of the BST we want to build. To keep the tree balanced, we want the middle element as the root, with roughly equal numbers of nodes on each side. The core challenge is efficiently finding the middle of a linked list (or avoiding the need to find it at all).
0 <= n <= 2 * 10^4 → O(n log n) and even O(n^2) pass within this bound, but an O(n) solution exists. The list can be empty, so the code must handle a null head.-10^5 <= Node.val <= 10^5 → Values fit comfortably in a 32-bit integer, no overflow concerns.Copy all values into an array first, then solve the array version of the problem: pick the middle element as the root and recurse on both halves. The only obstacle in this problem is that a linked list lacks random access, and an array restores it. The cost is O(n) extra space to duplicate the input.
Input:
Copying the list produces this array:
The recursion runs as follows:
build(0, 4): mid = 2, so 0 becomes the root. Recurse on indices 0 to 1 and 3 to 4.build(0, 1): mid = 0, so -10 becomes the root's left child. build(0, -1) returns null, and build(1, 1) makes -3 the right child of -10.build(3, 4): mid = 3, so 5 becomes the root's right child. build(3, 2) returns null, and build(4, 4) makes 9 the right child of 5.Resulting BST:
The array doubles the memory footprint of the input. The next approach drops it and works on the linked list in place.
Instead of copying everything into an array, we can work with the linked list directly. Slow and fast pointers find the middle of a list: the slow pointer moves one step for every two steps the fast pointer takes, so when fast reaches the end, slow is at the middle.
The middle node becomes the root of the current subtree. Everything before it is smaller (the list is sorted) and forms the left subtree; everything after it is larger and forms the right subtree, so the BST property holds at every node. The split also keeps the two halves within one node of each other in size, which is what makes the result height-balanced. We disconnect the left half by setting the previous node's next pointer to null, then recurse on both halves.
The single-node base case below is required for termination. With one node, the slow pointer never moves, prev stays null, nothing gets disconnected, and the left recursion would receive the same one-node list again and loop forever.
prev.next = null.This eliminates the extra array, but every recursion level re-scans its segment to find the middle, which is where the extra log n factor comes from. The list is already in in-order sequence, and the final approach uses that to read each node exactly once.
An in-order traversal of a BST visits nodes in sorted order, and our list is already sorted. So instead of searching for each subtree's root, we can run an in-order traversal that creates nodes instead of reading them: visit the positions of the balanced tree in in-order sequence and hand each one the next value from the list.
Count the total size of the list once, then recurse over index ranges, exactly as in the array version. The difference is that no call ever indexes into anything. When a call builds its left subtree over k indices, those k node creations consume the first k nodes from the list. Once the left subtree is finished, the shared list pointer sits at exactly the node that belongs at the current root. Create the root from it, advance the pointer, then build the right subtree from the remaining indices.
The midpoint computation still appears, but it only decides how many indices go to each side (which is what keeps the tree balanced). The values come from the list pointer, which moves forward one node per created tree node. Each node is read once, giving O(n) time.
build(left, right) where left and right are index bounds.left > right, return null (base case).mid = left + (right - left) / 2. This splits the index range; it is never used to read a value.build(left, mid - 1). This advances the list pointer past the left subtree's nodes.build(mid + 1, right).