力扣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;
}

参考来源

相关推荐
Alvin's Tech Blog1 小时前
内存泄漏会导致操作系统永久丢失内存吗?它会导致应用程序崩溃吗?
c++·内存管理·内存泄漏
会周易的程序员1 小时前
使用 LuaBridge 封装 C++ 日志库 microLog 为 Lua 模块
c++·物联网·junit·lua·日志·iot·aiot
2zcode1 小时前
项目文档:基于MATLAB图像处理的饮料瓶灌装液位检测系统设计与实现
开发语言·图像处理·matlab
月疯2 小时前
np.where()[0]的用法
开发语言·python·numpy
wbs_scy2 小时前
仿 muduo 高并发服务器项目:从 timerfd 到时间轮实现定时任务机制
linux·服务器·c++
aqiu1111112 小时前
【算法日记 13】LeetCode 49. 字母异位词分组:哈希表的进阶“降维打击”
算法·leetcode·散列表
z落落2 小时前
C#五大加密算法(AES、DES、MD5、RSA、SHA)
开发语言·c#
namexingyun2 小时前
Scaling Law bug实战启示:从“虚胖“到“精瘦“的算力效率革命
开发语言·网络·人工智能·bug·ai编程
KaMeidebaby2 小时前
卡梅德生物技术快报|纳米抗体技术全套实操流程:AFB1 全合成文库淘选 + 分子对接定点突变参数手册
人工智能·python·tcp/ip·算法·机器学习