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;
}
复制代码

 


posted @   ˙鲨鱼辣椒ゝ  阅读(60)  评论(0编辑  收藏  举报
编辑推荐:
· 从 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)
点击右上角即可分享
微信分享提示