#108 树分治 简单

将有序数组转换为二叉搜索树

在 LeetCode 上查看 ↗

🎧 语音讲解

开车或通勤时可听,跟着思路走一遍

速度

📋 题目描述

给你一个整数数组 nums,其中元素已经按升序排列,请你将其转换为一棵高度平衡的二叉搜索树。

高度平衡二叉树是指:每个节点的左右两个子树的高度差不超过 1。数组长度在 [1, 104] 内,元素严格递增。

示例 1

输入:nums = [-10,-3,0,5,9]
输出:[0,-3,9,-10,null,5]
取中点 0 为根;左段 [-10,-3] 根 -3、左子 -10;右段 [5,9] 根 9、左子 5。另一合法答案如 [0,-10,5,null,-3,null,9]。

示例 2

输入:nums = [1,3]
输出:[3,1] 或 [1,null,3](均为高度平衡 BST)

💭 模拟答题者思考

1. 暴力直觉:枚举所有 BST 形状再验证中序是否等于 nums——组合爆炸,不可行。

2. 关键观察:有序数组就是 BST 的中序遍历;只要为每个连续子段选定一个根,左段全是左子树、右段全是右子树,BST 性质自动满足。

3. 要「高度平衡」:子树节点数尽量对半分 → 每次取区间中点作根,左右子树规模差不超过 1,树高 O(log n)。

4. 子问题同型:dfs(left, right) 只依赖区间边界,与 #105/#106 一样是分治建树,但无需哈希表——下标即中序位置。

5. 示例 1:[-10,-3,0,5,9],根 mid=2 值 0;左 [-10,-3] 根 -3;右 [5,9] 根 9,左子 5。

🧠 变量语义(先读这三句再编码)

变量类型语义(三句法)
left, rightint定义:当前子树在有序数组 nums 上的闭区间下标
维护:left > right 表示空子树,返回 null
更新:根落在 mid 后,左子树 [left, mid-1]、右子树 [mid+1, right]
midint定义:当前区间的「中点」下标,其值作为子树根节点
维护:有序数组的中序遍历即自身,nums[mid] 满足 BST 中序性质
更新:常用 mid = (left + right) // 2(或偏左/偏右中点,多种答案均合法)
rootTreeNode*定义:当前区间对应的 BST 根,值为 nums[mid]
维护:先建根,再递归挂左、右子树(顺序任意)
更新:root.left = dfs(left, mid-1),root.right = dfs(mid+1, right)

⌨️ 落码步骤

1. 定义 dfs(left, right):若 left > right 返回 null

2. mid = (left + right) // 2,root = TreeNode(nums[mid])

3. root.left = dfs(left, mid - 1),root.right = dfs(mid + 1, right)

4. 返回 dfs(0, len(nums) - 1) 作为整棵树的根

💻 代码实现

class Solution:
    def sortedArrayToBST(self, nums: list[int]) -> TreeNode | None:
        def dfs(left: int, right: int) -> TreeNode | None:
            if left > right:
                return None
            mid = (left + right) // 2
            node = TreeNode(nums[mid])
            node.left = dfs(left, mid - 1)
            node.right = dfs(mid + 1, right)
            return node

        return dfs(0, len(nums) - 1)
class Solution {
    TreeNode* dfs(vector<int>& nums, int left, int right) {
        if (left > right) return nullptr;
        int mid = left + (right - left) / 2;
        auto* root = new TreeNode(nums[mid]);
        root->left = dfs(nums, left, mid - 1);
        root->right = dfs(nums, mid + 1, right);
        return root;
    }

public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        return dfs(nums, 0, (int)nums.size() - 1);
    }
};
// 时间 O(n),空间 O(n)

📈 复杂度分析

时间复杂度 O(n)
空间复杂度 O(n)(递归栈 O(log n)~O(n),共建 n 个节点)

⚠️ 常见坑

❗ 取根用 left 或 right 而非中点:仍可能是合法 BST,但会退化成链,不满足「高度平衡」。

❗ 右子树区间写成 [mid, right]:根已在 mid,右子树必须从 mid + 1 开始,否则会重复节点或破坏 BST。

❗ 整数溢出写法:mid = (left + right) / 2 在 C++ 里建议 left + (right - left) / 2(本题数据范围通常无碍,养成习惯)。

🔍 必测边界 Case

Case 1:单元素
nums = [0] → 单节点根 0
Case 2:两个元素
nums = [1,3] → 根 3 左子 1,或根 1 右子 3
Case 3:官方示例 1
nums = [-10,-3,0,5,9] → 中点根 0,左右子树各再取中点
Case 4:连续整数长链
nums = [1..7] → 中点分治得近似满二叉树,高度 3