105. 从前序与中序遍历序列构造二叉树
一、题目
给定两个整数数组 preorder
和 inorder
,其中 preorder
是二叉树的先序遍历, inorder
是同一棵树的中序遍历,请构造二叉树并返回其根节点。
二、思路
3 / \ 9 20 / / \ 8 15 7 / \ 5 10 / 4
preorder = [3, 9, 8, 5, 4, 10, 20, 15, 7] inorder = [4, 5, 8, 10, 9, 3, 15, 20, 7]
我们用一个栈 stack
来维护「当前节点的所有还没有考虑过右儿子的祖先节点」,栈顶就是当前节点。也就是说,只有在栈中的节点才可能连接一个新的右儿子。同时,我们用一个指针 index
指向中序遍历的某个位置,初始值为 0
。index
对应的节点是「当前节点不断往左走达到的最终节点」,这也是符合中序遍历的,它的作用在下面的过程中会有所体现。
首先我们将根节点 3
入栈,再初始化 index
所指向的节点为 4
,随后对于前序遍历中的每个节点,我们依次判断它是栈顶节点的左儿子,还是栈中某个节点的右儿子。
们遍历 9
。9
一定是栈顶节点 3
的左儿子。我们使用反证法,假设 9
是 3
的右儿子,那么 3
没有左儿子,index
应该恰好指向 3
,但实际上为 4
,因此产生了矛盾。所以我们将 9
作为 3
的左儿子,并将 9
入栈
三、代码
class Solution { public: TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { if (!preorder.size()) { return nullptr; } TreeNode* root = new TreeNode(preorder[0]); stack<TreeNode*> stk; stk.push(root); int inorderIndex = 0; for (int i = 1; i < preorder.size(); ++i) { int preorderVal = preorder[i]; TreeNode* node = stk.top(); if (node->val != inorder[inorderIndex]) { node->left = new TreeNode(preorderVal); stk.push(node->left); } else { while (!stk.empty() && stk.top()->val == inorder[inorderIndex]) { node = stk.top(); stk.pop(); ++inorderIndex; } node->right = new TreeNode(preorderVal); stk.push(node->right); } } return root; } };
四、分析
复杂度分析
-
时间复杂度:O(n),其中 n 是树中的节点个数。
-
空间复杂度:O(n)),除去返回的答案需要的 O(n) 空间之外,我们还需要使用 O(h)(其中 hhh 是树的高度)的空间存储栈。这里 h<n,所以(在最坏情况下)总空间复杂度为 O(n)。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了