LeetCode 109: Convert Sorted List to Binary Search Tree (Slow/Fast Mid Split Recursion)
LeetCode 109Linked ListBinary TreeDivide and ConquerToday we solve LeetCode 109 - Convert Sorted List to Binary Search Tree. Because the list is sorted, the middle node should become the root to keep the BST balanced.
Source: https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree/
English
Problem Summary
Given a singly linked list where values are sorted in ascending order, convert it into a height-balanced BST.
Key Insight
For every recursive segment of the list, pick its middle node as root. Nodes before mid become the left subtree; nodes after mid become the right subtree. Slow/fast pointers find this middle in linear time for each segment.
Optimal Algorithm (Recursive Mid Split)
1) Base case: empty segment returns null. Single node returns one tree node.
2) Use slow, fast, and prev to locate the middle node.
3) Cut list at prev.next = null so left half becomes an independent sublist.
4) Create root from slow.val.
5) Recursively build left subtree from head to prev, right subtree from slow.next.
6) Return root.
Complexity Analysis
Time: O(n log n) — each level scans list segments to find mids.
Space: O(log n) recursion depth for balanced splits.
Common Pitfalls
- Forgetting to disconnect the left half, causing infinite recursion.
- Not handling the single-node case separately.
- Using fast != null && fast.next != null without preserving prev, then unable to cut.
Reference Implementations (Java / Go / C++ / Python / JavaScript)
class Solution {
public TreeNode sortedListToBST(ListNode head) {
if (head == null) return null;
if (head.next == null) return new TreeNode(head.val);
ListNode prev = null, slow = head, fast = head;
while (fast != null && fast.next != null) {
prev = slow;
slow = slow.next;
fast = fast.next.next;
}
// split: head..prev | slow | slow.next..
prev.next = null;
TreeNode root = new TreeNode(slow.val);
root.left = sortedListToBST(head);
root.right = sortedListToBST(slow.next);
return root;
}
}func sortedListToBST(head *ListNode) *TreeNode {
if head == nil {
return nil
}
if head.Next == nil {
return &TreeNode{Val: head.Val}
}
var prev *ListNode
slow, fast := head, head
for fast != nil && fast.Next != nil {
prev = slow
slow = slow.Next
fast = fast.Next.Next
}
prev.Next = nil
root := &TreeNode{Val: slow.Val}
root.Left = sortedListToBST(head)
root.Right = sortedListToBST(slow.Next)
return root
}class Solution {
public:
TreeNode* sortedListToBST(ListNode* head) {
if (!head) return nullptr;
if (!head->next) return new TreeNode(head->val);
ListNode* prev = nullptr;
ListNode* slow = head;
ListNode* fast = head;
while (fast && fast->next) {
prev = slow;
slow = slow->next;
fast = fast->next->next;
}
prev->next = nullptr;
TreeNode* root = new TreeNode(slow->val);
root->left = sortedListToBST(head);
root->right = sortedListToBST(slow->next);
return root;
}
};class Solution:
def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
if not head:
return None
if not head.next:
return TreeNode(head.val)
prev = None
slow = fast = head
while fast and fast.next:
prev = slow
slow = slow.next
fast = fast.next.next
prev.next = None
root = TreeNode(slow.val)
root.left = self.sortedListToBST(head)
root.right = self.sortedListToBST(slow.next)
return root/**
* @param {ListNode} head
* @return {TreeNode}
*/
var sortedListToBST = function(head) {
if (!head) return null;
if (!head.next) return new TreeNode(head.val);
let prev = null;
let slow = head;
let fast = head;
while (fast && fast.next) {
prev = slow;
slow = slow.next;
fast = fast.next.next;
}
prev.next = null;
const root = new TreeNode(slow.val);
root.left = sortedListToBST(head);
root.right = sortedListToBST(slow.next);
return root;
};中文
题目概述
给定一个升序单链表,要求将其转换为一棵高度平衡的二叉搜索树(BST)。
核心思路
每次递归都取当前链表片段的中点作为根节点,这样左半部分构成左子树,右半部分构成右子树,整体保持平衡。链表中点可以用快慢指针在线性时间找到。
最优算法(递归 + 快慢指针切分)
1)空链表返回 null;单节点直接建树返回。
2)使用 slow/fast/prev 找中点。
3)执行 prev.next = null 将左半链表断开。
4)中点 slow 作为根节点。
5)左子树递归处理原头结点,右子树递归处理 slow.next。
6)返回根节点。
复杂度分析
时间复杂度:O(n log n),每层递归要扫描片段找中点。
空间复杂度:O(log n),递归深度约为树高。
常见陷阱
- 忘记断开左半链表,导致递归无法收敛。
- 没有单节点特判,prev 可能为空并引发错误。
- 切分边界处理不严谨,造成左右子树错位。
多语言参考实现(Java / Go / C++ / Python / JavaScript)
class Solution {
public TreeNode sortedListToBST(ListNode head) {
if (head == null) return null;
if (head.next == null) return new TreeNode(head.val);
ListNode prev = null, slow = head, fast = head;
while (fast != null && fast.next != null) {
prev = slow;
slow = slow.next;
fast = fast.next.next;
}
prev.next = null;
TreeNode root = new TreeNode(slow.val);
root.left = sortedListToBST(head);
root.right = sortedListToBST(slow.next);
return root;
}
}func sortedListToBST(head *ListNode) *TreeNode {
if head == nil {
return nil
}
if head.Next == nil {
return &TreeNode{Val: head.Val}
}
var prev *ListNode
slow, fast := head, head
for fast != nil && fast.Next != nil {
prev = slow
slow = slow.Next
fast = fast.Next.Next
}
prev.Next = nil
root := &TreeNode{Val: slow.Val}
root.Left = sortedListToBST(head)
root.Right = sortedListToBST(slow.Next)
return root
}class Solution {
public:
TreeNode* sortedListToBST(ListNode* head) {
if (!head) return nullptr;
if (!head->next) return new TreeNode(head->val);
ListNode* prev = nullptr;
ListNode* slow = head;
ListNode* fast = head;
while (fast && fast->next) {
prev = slow;
slow = slow->next;
fast = fast->next->next;
}
prev->next = nullptr;
TreeNode* root = new TreeNode(slow->val);
root->left = sortedListToBST(head);
root->right = sortedListToBST(slow->next);
return root;
}
};class Solution:
def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
if not head:
return None
if not head.next:
return TreeNode(head.val)
prev = None
slow = fast = head
while fast and fast.next:
prev = slow
slow = slow.next
fast = fast.next.next
prev.next = None
root = TreeNode(slow.val)
root.left = self.sortedListToBST(head)
root.right = self.sortedListToBST(slow.next)
return root/**
* @param {ListNode} head
* @return {TreeNode}
*/
var sortedListToBST = function(head) {
if (!head) return null;
if (!head.next) return new TreeNode(head.val);
let prev = null;
let slow = head;
let fast = head;
while (fast && fast.next) {
prev = slow;
slow = slow.next;
fast = fast.next.next;
}
prev.next = null;
const root = new TreeNode(slow.val);
root.left = sortedListToBST(head);
root.right = sortedListToBST(slow.next);
return root;
};
Comments