↓Skip to main content
  1. LeetCode/

LeetCode 109: Convert Sorted List to Binary Search Tree

·2 mins· ·
LeetCode Medium Linked-List Divide-and-Conquer Tree Binary-Search-Tree
Wei Yi Chung
Author
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
Table of Contents

Meta Data
#

Difficulty: medium First Attempt: 2022-11-19

  • Submissions: Wrong Answer ×2 → Runtime Error ×3 → Accepted ×4

Approach
#

A balanced BST has its root in the middle (Linked List Template 3):

  1. Find the middle with fast and slow pointers, remembering the node before it to cut off the left half.
  2. The middle becomes the root; recurse on the left and right halves.

Every level splits at the middle, so the two sides differ by at most one and the height is balanced.

My Attempts
#

The first two versions grew the tree outward from the middle with two pointers, padding with TreeNode(None) when the sides differed in length, which added nodes whose value was None: [1, 3] had in-order [1, 3, None]. Switching to recursive halving passed.

Solution
#

class Solution:
    def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
        if not head:
            return None
        if not head.next:
            return TreeNode(head.val)
        prev, slow, fast = None, head, head
        while fast and fast.next:
            prev, slow, fast = slow, slow.next, fast.next.next
        prev.next = None                           # 切斷左半邊
        return TreeNode(slow.val, self.sortedListToBST(head), self.sortedListToBST(slow.next))

Complexity
#

Time O(n log n) (finding middles costs O(n) per level), space O(log n). Converting to an array first gives O(n) time.

Mistakes to Avoid
#

  • Keep the node before the middle so the left half can be cut off.
  • Return directly for a single node, or the left half cannot be split.

Interview Explanation
#

I use fast and slow pointers to find the middle as the root, cut the left half off before it, and recurse on both halves. Always splitting in the middle keeps the height balanced. Time O(n log n).

Related

LeetCode 116: Populating Next Right Pointers in Each Node
·2 mins
LeetCode Medium Linked-List Tree Depth-First-Search Breadth-First-Search
LeetCode 116 note: in a perfect binary tree, walk each level through the next pointers already set on the level above: left.next = right and right.next = next.left, with O(1) extra space
LeetCode 148: Sort List
·2 mins
LeetCode Medium Linked-List Two-Pointers Divide-and-Conquer Sorting
LeetCode 148 note: split in half with fast and slow pointers, sort each half recursively and merge; O(n log n) with no extra array
LeetCode 106: Construct Binary Tree from Inorder and Postorder Traversal
·1 min
LeetCode Medium Array Hash-Table Divide-and-Conquer Tree
LeetCode 106 note: the last post-order value is the root; taking roots from the end of the post-order, build the right subtree before the left
LeetCode 105: Construct Binary Tree from Preorder and Inorder Traversal
·2 mins
LeetCode Medium Array Hash-Table Divide-and-Conquer Tree
LeetCode 105 note: the first pre-order value is the root, and its position in the in-order tells the left subtree’s size; look positions up in a dictionary for O(n)
LeetCode 230: Kth Smallest Element in a BST
·1 min
LeetCode Medium Tree Depth-First-Search Binary-Search-Tree Binary-Tree
LeetCode 230 note: a BST’s in-order traversal is ascending, so stop an iterative in-order walk at the k-th node
LeetCode 98: Validate Binary Search Tree
·2 mins
LeetCode Medium Tree Depth-First-Search Binary-Search-Tree Binary-Tree
LeetCode 98 note: every node has a valid range (low, high); going left the upper bound becomes the node and going right the lower bound does; comparing parent and child is not enough