Leecode 105-从前序与中序遍历序列构造二叉树

该博客介绍了如何根据二叉树的前序遍历和中序遍历结果来构建二叉树。通过分治算法,首先找到根节点,然后利用哈希表快速查找中序遍历中根节点的位置,进一步划分左右子树,递归构建左右子树,最终形成完整的二叉树结构。代码实现中使用了Java的TreeNode类,并展示了关键的递归函数`recur`。
摘要由CSDN通过智能技术生成

同剑指offer 07 - 重建二叉树/LCR 124

题目描述

输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。

假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

题解

题解可参考代码随想录

分治算法模版

//终止条件:左边界越过右边界
if(left>right) break;

//根据题目条件找到pivot
//划分数组为(left,pivot-1)和(pivot+1,right)
//如果是二叉树,则有root.left=dfs(nums,left,pivot-1),root.right=dfs(pivot+1,right)

//继续找左右数组的pivot,继续划分左右数组直至终止

分治算法解析:

一、当前需做的步骤:
1.前序遍历的第一个节点为根节点
2.分治中序数组:在中序遍历中搜索根节点 的索引,将中序遍历结果划分为 [ 左子树 | 根节点 | 右子树 ] ,由此得到左右子树数目
3.分治前序数组:根据左右子树数目去将前序遍历划分为[ 根节点 | 左子树 | 右子树 ] 。

二、继续分治:
1.根据前序的性质,可以得到左子树的根节点和右子树的根节点
可以继续通过划分中序序列划分左右子树,将左右子树继续化划分下去,即root.left=dfs(前序序列,前序左子树左边界,前序左子树右边界,中序序列,中序左子树左边界,中序左子树右边界)

三、返回条件
前序遍历左边界越过右边界||中序遍历左边界越过右边界

为了提升效率,本文使用哈希表 dic 存储中序遍历的值与索引的映射,查找操作的时间复杂度为 O(1) ;
在这里插入图片描述

代码实现

 //递归+分治
 /*
 一、当前需做的步骤:
 1.前序遍历的第一个节点为根节点
 2.分治中序数组:通过根节点将中序遍历结果划分为左中右,由此得到左右子树数目
 3.分治前序数组:根据左右子树数目去将前序遍历划分为中左右

 
 二、继续分治:
 1.根据前序的性质,可以得到左子树的根节点和右子树的根节点(可以继续通过划分中序序列划分左右子树),将左右子树继续化划分下去,即root.left=dfs(前序序列,前序左子树左边界,前序左子树右边界,中序序列,中序左子树左边界,中序左子树右边界)

 三、返回条件
前序遍历左边界越过右边界||中序遍历左边界越过右边界

 */
class Solution {
    HashMap<Integer,Integer> map = new HashMap<>();
    public TreeNode deduceTree(int[] preorder, int[] inorder) {
        
        //将中序遍历的值及索引放在map中,避免后续需要遍历中序数组寻找root的下标值,将找root下标这一步骤时间复杂度由O(n)变为O(1)
            for(int i=0;i<inorder.length;i++){
                map.put(inorder[i],i);
            }
            return recur(preorder,0,preorder.length-1,inorder,0,inorder.length-1);
     }

        //记住这里左闭右闭
        //需要两个遍历序列的左右边界值是因为需要对两个遍历序列都进行分治
        public TreeNode recur(int[] preorder,int preLeft,int preRight,int[] inorder,int inLeft,int inRight){
            //终止条件:分治前序数组或中序数组时左边界越过右边界
            if(preLeft>preRight||inLeft>inRight) return null;

            //获得根节点
            TreeNode root = new TreeNode(0);
            root.val=preorder[preLeft];

            //通过根节点将中序遍历结果划分为左中右,由此得到左右子树数目
            //这里用查找map替代了遍历中序数组查找root节点的下标
            //mid:根节点的index
            int mid = map.get(preorder[preLeft]);
            

            //分别分治前序数组和中序数组
            /*
            1.中序数组分治为(inLeft,mid-1)(mid+1,inRight)
            2.可得出左子树长度为(mid-inLeft),右子树长度为(inRight-mid-2)
            3.前序数组分治为(preLeft+1,preLeft+mid-inLeft)(preLeft+mid-inLeft+1,preRight)
            */

            root.left=recur(preorder,preLeft+1,preLeft+mid-inLeft,inorder,inLeft,mid-1);
            root.right=recur(preorder,preLeft+mid-inLeft+1,preRight,inorder,mid+1,inRight);

            //返回值
            return root;
        }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值