一、题目是啥?一句话说清
给你一个升序排列的单链表,将其转换为高度平衡的二叉搜索树(BST),即每个节点的左右子树高度差不超过1。
示例:
- 输入:head = [-10, -3, 0, 5, 9]
- 输出:一个平衡BST,例如 [0, -3, 9, -10, null, 5](树的形式,根节点为0,左子树为-3,右子树为9,等等)
二、解题核心
使用快慢指针找到链表的中间节点作为二叉搜索树的根节点,然后递归构建左子树和右子树。 这就像找到一群按身高排序的人中的中间那个人作为队长,然后让左边的人组成左队,右边的人组成右队,递归进行直到所有人都安排到位。
三、关键在哪里?(3个核心点)
想理解并解决这道题,必须抓住以下三个关键点:
1. 快慢指针找中间节点
- 是什么:快指针每次走两步,慢指针每次走一步,当快指针到达链表末尾时,慢指针指向中间节点。
- 为什么重要:中间节点作为BST的根节点,可以确保树是平衡的,因为左右子树的节点数大致相等。
2. 递归构建子树
- 是什么:找到中间节点后,将链表分为左半部分和右半部分,递归构建左子树和右子树。
- 为什么重要:递归是构建树结构的关键,每次递归处理子链表,确保每个子树都是平衡的。
3. 链表断开处理
- 是什么:在找到中间节点后,需要将左半部分的链表末尾断开,以便递归处理左半部分时不会包含中间节点及其后的节点。
- 为什么重要:如果不断开链表,递归时会处理错误的节点范围,导致树结构错误。
四、看图理解流程(通俗理解版本)
让我们用链表 [-10, -3, 0, 5, 9] 的例子来可视化过程:
找到中间节点:
- 快慢指针初始化:快指针和慢指针都指向头节点 -10。
- 快指针移动两步(到0),慢指针移动一步(到-3)。
- 快指针移动两步(到9),慢指针移动一步(到0)。
- 快指针到达末尾,慢指针指向0,即中间节点。
构建根节点:
- 以中间节点0的值创建根节点。
断开链表:
- 左半部分链表:从头节点 -10 到中间节点0的前一个节点 -3(需要断开,使 -3 的 next 为 null)。
- 右半部分链表:中间节点0的下一个节点5开始到末尾。
递归构建左子树:
- 左半部分链表:[-10, -3]
- 找到中间节点:快慢指针找到 -3 作为中间节点(因为链表较短,-3 是中间)。
- 以 -3 为根,左子树为 -10,右子树为 null。
递归构建右子树:
- 右半部分链表:[5, 9]
- 找到中间节点:快慢指针找到 5 作为中间节点(但实际中间应该是9?需要正确处理)。
- 以 5 为根,左子树为 null,右子树为 9。
组合成树:
- 根节点0的左子树指向 -3,右子树指向 5。
- 最终树结构:
0
/
-3 5
/
-10 9
注意:实际过程中,递归会正确处理链表长度,确保树平衡。
五、C++ 代码实现(附详细注释)
#include <iostream>
using namespace std;
// 链表节点定义
struct ListNode {
int val;
ListNode *next;
ListNode() : val(0), next(nullptr) {
}
ListNode(int x