力扣1008:前序重建BST

力扣 1008 题解析与 C++ 代码

一、问题解析题目描述 :给定一个整数数组 preorder,表示二叉搜索树(BST)的前序遍历 结果,请重建该二叉搜索树并返回其根节点。题目保证对于给定的测试用例,总能找到一棵二叉搜索树与之对应。

核心要点

  1. 二叉搜索树(BST)性质:对于任意节点,其左子树所有节点值 < 该节点值 < 右子树所有节点值。
  2. 前序遍历顺序:根节点 → 左子树 → 右子树。
  3. 重建思路:前序遍历的第一个元素是根节点,随后连续小于根节点的部分是左子树的前序遍历,剩余部分是右子树的前序遍历。递归应用此规则即可重建整棵树。

算法步骤

  1. 取当前区间 [start, end] 的第一个元素作为根节点值。
  2. 找到第一个大于根节点值的索引 mid,该索引将区间划分为左子树 [start+1, mid-1] 和右子树 [mid, end]
  3. 递归构建左子树和右子树。
  4. 返回根节点。

时间复杂度 :O(n²),最坏情况(如斜树)每次需线性扫描划分左右子树。可优化至 O(n)(见后续优化方案)。

空间复杂度:O(n),递归栈深度。

二、C++ 代码实现

基础递归解法

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* bstFromPreorder(vector<int>& preorder) {
        return build(preorder, 0, preorder.size() - 1);
    }

private:
    TreeNode* build(vector<int>& preorder, int start, int end) {
        if (start > end) return nullptr;
 // 当前子树的根节点是前序遍历的第一个元素 TreeNode* root = new TreeNode(preorder[start]);
 // 找到第一个大于根节点值的索引,划分左右子树 int mid = start + 1;
        while (mid <= end && preorder[mid] < preorder[start]) {
            mid++;
        }
 // 递归构建左右子树 root->left = build(preorder, start + 1, mid1);
        root->right = build(preorder, mid, end);
        
        return root;
    }
};

优化解法(O(n) 时间复杂度)

利用单调栈模拟递归过程,一次遍历完成构建:

cpp 复制代码
class Solution {
public:
    TreeNode* bstFromPreorder(vector<int>& preorder) {
        if (preorder.empty()) return nullptr;
 stack<TreeNode*> stk;
        TreeNode* root = new TreeNode(preorder[0]);
 stk.push(root);
        
        for (int i = 1; i < preorder.size(); i++) {
            TreeNode* node = new TreeNode(preorder[i]);
            
            if (preorder[i] < stk.top()->val) {
                // 当前值小于栈顶,作为左子节点
                stk.top()->left = node;
            } else {
                // 当前值大于栈顶,找到合适的父节点 TreeNode* parent = nullptr;
                while (!stk.empty() && preorder[i] > stk.top()->val) {
                    parent = stk.top();
                    stk.pop();
                }
                parent->right = node;
            }
            
            stk.push(node);
        }
 return root;
    }
};

三、算法对比

特性 基础递归解法 优化栈解法
时间复杂度 O(n²) O(n)
空间复杂度 O(n) O(n)
核心思想 递归划分左右子树 单调栈维护节点关系
适用场景 数据量较小 数据量较大或要求高效
代码复杂度 简单直观 稍复杂但高效

四、关键点说明

  1. 边界处理 :递归解法中需确保 start > end 时返回 nullptr,避免无限递归。
  2. 划分点查找:基础解法中线性查找第一个大于根节点的索引,是 O(n²) 复杂度的根源。
  3. 单调栈原理:优化解法利用栈保存尚未设置右子树的节点,遇到更大值时弹出栈顶直到找到合适父节点,确保 BST 性质。
  4. 相关题目:本题与力扣 105(从前序与中序遍历构造二叉树)思路相似,但 BST 性质使得无需中序遍历即可确定左右子树边界。

五、测试示例

cpp 复制代码
// 测试代码示例
int main() {
    Solution solution;
    vector<int> preorder = {8, 5, 1, 7, 10, 12};
    TreeNode* root = solution.bstFromPreorder(preorder);
 // 中序遍历验证(BST 中序遍历应为升序)
    // 预期输出:1 5 7 8 10 12 return 0;
}

参考来源

相关推荐
小玮看世界3 分钟前
[Python]螺旋遍历 vs 最短路径:方向控制类算法的“同源异流”
开发语言·python·算法
月华路8 分钟前
《模型不玄学》第14章 标签、损失与样本权重
人工智能·算法·机器学习
黄金龙PLUS10 分钟前
SPARKLE置换算法的优缺点
算法·网络安全·密码学·哈希算法·同态加密
不会就选b10 分钟前
算法日常・每日刷题--<贪心>3
数据结构·算法·leetcode
学习星球13 分钟前
编辑距离——二维 DP 的“最小操作“艺术
c++·leetcode·java-consul
OPEN-F13 分钟前
ROS2系列教程:tf2坐标变换详解(C++/Python)
开发语言·c++·python
暖焰核心16 分钟前
迭代器与模板的结合——stl的list
c++·windows·list
行者全栈架构师18 分钟前
WorkBuddy 实战:把一份 200 页年报变成可上台的投资分析 PPT
人工智能·算法·全栈
XR12345678823 分钟前
医院基础网络改造升级选型深度解析
开发语言·网络·php
reasonsummer24 分钟前
【办公类-146-05】20260901《一分园、二分园四大教育》(优化版:标题excle+复制AI文字+Python占位符录入)
开发语言·数据库·c#