Leetcode刷题-105:从前序与中序遍历序列构造二叉树

1.题目描述

给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

示例1:
在这里插入图片描述

输入:preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出:[3,9,20,null,null,15,7]

2.题目分析:

2.1 知识迁移——递归与二叉树

一般来说涉及二叉树的遍历问题的话,我们应该首先都可以想到利用递归的方法来切入,因为二叉树就其本身而言就是一个递归性质的树,我们可以首先抛开编码,设想自己在画树的时候如何构建一个给出前中序遍历的树。
首先我们来回顾一下二叉树的遍历方法

  • 前序遍历:先遍历根节点,然后遍历其左子树,最后遍历右子树
  • 中序遍历:先遍历其左子树,然后遍历根节点,最后是遍历右子树
  • 后序遍历:先遍历其左子树,后遍历其右子树,最后遍历根节点

不难发现常规的二叉树遍历都是左子树位于右子树之前(注意非常规的情况)。分析上面的遍历性质,很容易可以得到,对于前序遍历来说,第一个元素必然是树的根节点,而对于一个树的中序遍历来说,其根节点必然中序遍历序列分为左右两个部分,分别对应左子树和右子树。在此基础上所有的子树也是遵照这个性质的我们知道了这一点性质就可以用来解题了。我们总结出以下递归方法

  1. 首先在长度为n前序序列中找到当前树的根节点,再找到根节点在中序序列中的位置i; 此时中序序列中的0~i-1就是左子树,i ~n就是右子树
  2. 我们可以继续按照性质分别构造左右子树,也就是在前序序列中分别找到左右子树的root节点,然后继续在中序序列中划分左右子树的左右子树。(我们需要考虑子树为空的情况)
  3. 构造完左右子树后,输出树的根节点

2.2 实例分析

拿上面的示例分析,我们首先确定前序序列中的第一个元素3为树的根节点,此时在中序序列中找到3的位置并按照其将序列划分为左右两部分分别为左右子树

3,9,20,15,7
[9],3,[15,20,7]

此时再构造左子树,左子树只有一个节点,其自己为自己的根节点;
继续构造右子树,查询前序序列发现20为右子树的根节点,再在中序序列中查询20,并按照这个节点将右子树划分为左右两部分,分别为15和7,至此树构造完成。

3,9,20,15,7
[9],3,[15],20,[7]

在这里插入图片描述
在解题中对于中序遍历中的根节点位置求法我首先使用的是使用find函数库函数来进行查找,但是find函数的返回值是一个迭代器指针,使用的话还要继续再求迭代器距离,较为繁琐也容易出错,参考官方解答使用一个hashmap首先对于每个节点的位置进行存储,这样就可以牺牲一些空间来达到代码的简洁性,时间上来说可能也更高效。另外只要使用到指针我们必然要避免指针溢出的问题,尤其是指针参与到循环当中,必然要格外注意这个问题。在实际解题过程中,我们必然会碰到左子树或者右子树为空的情况,此时我们就要理清指针溢出的思路。假如是一个子树为空,我们可以得到其preorderLeft必然是大于preorderRight的,所以在每次递归前我们首先要对此做出判定,否则会因指针指向而出错。

2.3 迭代解法分析

我们也可以采用非递归的方式来进行解题,不过非递归的方式的处理逻辑就比较复杂一点了。跟递归方法一样,也是要以前序为基础,中序为参照来划分树的节点。首先来观察二叉树的前序遍历序列,我们会发现,对于两个相邻的节点u和v,他们的关系有以下几种情况:

  • v是u的左孩子
  • v是u的某个祖先的右孩子
  • v是u的右孩子

假设有下面的一个树
在这里插入图片描述

我们接下来分析上面的树的构建,首先我们维护一个栈st来保存没有处理过右孩子的节点,中序遍历处理下标index=0

这里解释一下index的含义,如果index所指的值与栈顶元素相同,就说明这个栈顶元素必然没有左孩子(此时中序序列中index指向的值左边都已经处理过,也就是该节点中序遍历左边是没有元素了),此时就可以说明当前处理的节点preorder[i]是一个右孩子。
index所指的值与栈顶元素不相同,就说明栈顶元素是有左孩子的,而且preorder[i]必然是其左孩子

  • 初始化根节点为1,节点1入栈,st=[1]
  • 处理前序序列中的2,此时2在中序序列中位于1的左边,所以他只能是1的左孩子,2入栈。st=[1,2]
  • 继续处理前序序列中的4,类似前一步可以知道4是2的左孩子,4入栈。st=[1,2,4]
  • 处理5,此时我们发现栈顶元素等于index指向的值,那么5就是一个右孩子,因此我们进行栈顶元素出栈的同时对index+1,当栈顶元素对index所指的元素不相同,就说明5是这个节点的右孩子,我们得出5是2的右孩子,index=2。st=[1,5]
  • 处理节点7,st=[1
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值