力扣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 分钟前
自学嵌入式第N天(Linux篇——文件编程)
java·开发语言·前端
richard_yuu12 分钟前
JSON vs XML vs 二进制:3种序列化终极选型
xml·c++·qt·学习·json
没落之王25 分钟前
易学使者郑氏正脉郑冰推演马航事件
大数据·人工智能·算法·机器学习·可用性测试
caimouse42 分钟前
ReactOS 图形系统分析(33):字体子系统 — font.c
c语言·开发语言·reactos
阿部多瑞 ABU43 分钟前
告别手工核图:基于 .NET + MuPDFCore 的 CAD 等轴测 PDF 材料表提取与新旧版本对比实战
后端·算法·ui·pdf·c#
郝学胜-神的一滴1 小时前
并查集深度入门:从玄学抽象到 QuickFind & QuickUnion 源码实战
数据结构·c++·python·程序人生·算法·软件开发
比奇堡裤头村1 小时前
统计学习方法——决策树
算法·决策树·学习方法
cxr8281 小时前
HyperMind Lab M1 架构地基 Implementation Plan <二>
开发语言·人工智能·架构
灵晔君1 小时前
【Linux】进程控制(一)——进程创建、进程终止与进程等待
linux·c语言·算法
特立独行的猫a1 小时前
Tauri v2的Rust应用 → HarmonyOS(鸿蒙 PC)移植30分钟速成指南
开发语言·rust·harmonyos·tauri·移植·鸿蒙pc