105. 从前序与中序遍历序列构造二叉树
题目描述:
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
提示:
- 1 <= preorder.length <= 3000
- inorder.length == preorder.length
- -3000 <= preorder[i], inorder[i] <= 3000
- preorder 和 inorder 均 无重复 元素
- inorder 均出现在 preorder
- preorder 保证 为二叉树的前序遍历序列
- inorder 保证 为二叉树的中序遍历序列
解题思路:
对于前序遍历,它的形式总是:
[ 根节点, [左子树的前序遍历结果], [右子树的前序遍历结果] ]
而中序遍历的形式为:
[ [左子树的中序遍历结果], 根节点, [右子树的中序遍历结果] ]
在前序遍历中找到第一个数便是根节点,然后在中序遍历中定位这个根节点。中序遍历中,根节点左边的便是左子树的节点,根节点的右边便是右子树的节点,同时也能确定左右子树的节点数量。根据节点数量,我们可以将前序遍历的后续元素进行划分,哪些是左子树的前序遍历,哪些是右子树的前序遍历。同理,在左子树的前序遍历中找到的第一个数便是左子树的根节点,再用这个根节点在左子树中序遍历中定位根节点位置,重复上述步骤,直到划分出的序列为空。
var buildTree = function(preorder, inorder) { if(preorder.length == 0){ return null; } let root_value = preorder[0]; //找到根节点 let root = new TreeNode(root_value); let idx = inorder.indexOf(root_value);//在中序遍历中定位根节点位置 let leftTree_num = idx ; //位置的序号其实就是左子树的节点数量(右子树节点数量可以根据这个求解出来) root.left = buildTree(preorder.slice(1,1+leftTree_num),inorder.slice(0,idx));//使用slice()来划分出左子树的前序和中序遍历,当slice()函数的两个参数一样时,返回的是一个空子列 root.right = buildTree(preorder.slice(1+leftTree_num),inorder.slice(idx+1));//使用slice()来划分出右子树的前序和中序遍历 return root; };
计算过程:
当给定数组很大的时候,我们会发现使用 inorder.indexOf(root_value) 来查找会很费时。因此我们考虑使用哈希表来存储中序遍历,每次使用哈希表来查找根节点位置,将查找的时间复杂度降为O(1)。但如果我们仍使用slice()分割出子数组来进行递归,我们会发现子数组中根节点的位置跟原始的inorder数组的位置不一样,哈希表就失效了。因此下面我们不再使用slice()来分割数组,而是采用多个指针来分别指向左右子树的起始和结束节点位置。
var buildTree = function(preorder, inorder) { let len = preorder.length; let map = new Map(); for(let i=0;i<inorder.length;i++){ map.set(inorder[i],i); } return myBuild(preorder,inorder,0,len-1,0,len-1,map); }; function myBuild(preorder,inorder,p_start,p_end,i_start,i_end,map){ if(p_start>p_end){ return null; } let root_value = preorder[p_start]; let root_index = map.get(root_value); let left_numNode = root_index - i_start; let root = new TreeNode(root_value); root.left = myBuild(preorder,inorder,p_start+1,p_start+left_numNode,i_start,root_index-1,map); root.right = myBuild(preorder,inorder,p_start+left_numNode+1,p_end,root_index+1,i_end,map); return root; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)