题解 | #重建二叉树#

重建二叉树

http://www.nowcoder.com/practice/8a19cbe657394eeaac2f6ea9b0f6fcf6

算法思想一:递归

解题思路:

二叉树的前序遍历:左右;中序遍历:左根右
由前序遍历知道根节点之后,能在中序遍历上划分出左子树和右子树。分别对中序遍历的左右子树递归进行这一过程即可建树。

代码展示:

Python版本
class Solution:
    # 返回构造的TreeNode根节点
    def reConstructBinaryTree(self, pre, tin):
        # write code here
        if not pre:
            return None
        # 根节点
        root = TreeNode(pre[0])
        # 根节点在中序遍历中的位置索引
        tmp = tin.index(pre[0])
        # 递归 构造树的左子树
        root.left = self.reConstructBinaryTree(pre[1:tmp+1], tin[:tmp])
        # 递归构造树的右子树
        root.right = self.reConstructBinaryTree(pre[tmp+1:], tin[tmp+1:])
        return root

复杂度分析:

时间复杂度O(N):N表示二叉树的结点数量
空间复杂度O(N):返回的树占用空间

算法思想二:指针

解题思路:

二叉树的前序遍历:左右;中序遍历:左根右
设置三个指针,一个是preStart,表示的是前序遍历开始的位置,一个是inStart,表示的是中序遍历开始的位置。一个是inEnd,表示的是中序遍历结束的位置,我们主要是对中序遍历的数组进行拆解
图解:
前序序列:【1,2,3,4,5,6,7】
中序遍历:【3,2,4,1,6,5,7】
只要找到了前序遍历的结点在中序遍历的位置,我们就可以把中序遍历数组分解为左右子树两部分。
1、如果index是前序遍历的某个值在中序遍历数组中的索引,以index为根节点划分,在中序遍历中,[0,index-1]就是根节点左子树的所有节点,[index+1,tin.length-1]就是根节点右子树的所有节点
2、对于前序序列,针对左子树,preStart=index+1,如果是右子树就稍微麻烦点,preStart=preStart+(index-inStart+1),preStart是当前节点比如m先序遍历开始的位置,index-inStart+1就是当前节点m左子树的数量加上当前节点的数量,所以preStart+(index-instart+1)就是当前节点m右子树前序遍历开始的位置

代码展示:

JAVA版本
public class Solution {
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
        return dfs(0, 0, in.length - 1, pre, in);
    }
    
    public TreeNode dfs(int preStart, int inStart, int inEnd, int[] preorder, int[] inorder) {
        if (preStart > preorder.length - 1 || inStart > inEnd) {
            return null;
        }
        //创建结点
        TreeNode root = new TreeNode(preorder[preStart]);
        int index = 0;
        //找到当前节点root在中序遍历中的位置,然后再把数组分两半
        for (int i = inStart; i <= inEnd; i++) { if (inorder[i] == root.val) { index = i; break; } } root.left = dfs(preStart + 1, inStart, index - 1, preorder, inorder); root.right = dfs(preStart + index - inStart + 1, index + 1, inEnd, preorder, inorder); return root; }

复杂度分析:

时间复杂度O(N):N表示二叉树的结点数量
空间复杂度O(N):返回的树空间,使用额外指针,常数级空间

算法思想三:栈

解题思路:

二叉树的前序遍历:左右;中序遍历:左根右
借助栈来解决问题需要关注一个问题,就是前序遍历挨着的两个值比如m和n,它们会有下面两种情况之一的关系。
1、n是m左子树节点的值。
2、n是m右子树节点的值或者是m某个祖先节点的右节点的值。
对于第一种情况很容易理解,如果m的左子树不为空,那么n就是m左子树节点的值。
对于第二种情况,如果一个结点没有左子树只有右子树,那么n就是m右子树节点的值,如果一个结点既没有左子树也没有右子树,那么n就是m某个祖先节点的右节点,只要找到这个祖先节点就可以

代码展示:

JAVA版本
public class Solution {
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
        if (pre.length == 0)
            return null;
        Stackstack = new Stack<>();
        //前序的第一个其实就是根节点
        TreeNode root = new TreeNode(pre[0]);
        TreeNode cur = root;
        for (int i = 1, j = 0; i < pre.length; i++) { //第一种情况 if (cur.val != in[j]) { cur.left = new TreeNode(pre[i]); stack.push(cur); cur = cur.left; } else { //第二种情况 j++; //找到合适的cur,然后确定他的右节点 while (!stack.empty() && stack.peek().val == in[j]) { cur = stack.pop(); j++; } //给cur添加右节点 cur = cur.right = new TreeNode(pre[i]); } } return root; } }

复杂度分析:

时间复杂度O(N):N表示二叉树的结点数量
空间复杂度O(1):额外的栈空间(N个元素),返回树空间
全部评论
这个栈的思路,妙啊!
2 回复 分享
发布于 2022-09-04 14:26 广东
输出结果可以详细说说吗
点赞 回复 分享
发布于 2024-08-16 15:40 广东
递归方法里的index方法难道时间复杂度不是O(n)吗,这样这话 T(n) = 2T(n/2) + O(n) = ... = O(nlogn)
点赞 回复 分享
发布于 2024-06-09 21:54 贵州
栈的方法的时间复杂度真的是O(n)吗?for嵌套了一个while找祖先结点的话是n^2吗?空间复杂度是O(n)
点赞 回复 分享
发布于 2023-01-16 13:11 江苏
import java.util.*; /** * Definition for binary tree * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ //非常感谢大神啊,java的代码可以参照我的 public class Solution { public TreeNode reConstructBinaryTree(int [] pre,int [] vin) { if(pre.length == 0) return null; TreeNode root = new TreeNode(pre[0]); int index = -1; for(int i = 0;i < vin.length;i++) { if(vin[i] == pre[0]) { index = i; } } int[] pre1 = Arrays.copyOfRange(pre, 1, index+1); int[] pre2 = Arrays.copyOfRange(pre, index+1, pre.length); int[] vin1 = Arrays.copyOfRange(vin, 0, index); int[] vin2 = Arrays.copyOfRange(vin, index+1, vin.length); root.left = reConstructBinaryTree(pre1, vin1); root.right = reConstructBinaryTree(pre2, vin2); return root; } }
点赞 回复 分享
发布于 2022-01-15 10:24

相关推荐

03-13 00:04
已编辑
吉林大学 Java
约面的挺突然。。狠下心接了1.自我介绍2.讲讲JAVA的反射3.可以继续讲讲AOP,动态代理[&nbsp;因为讲反射不小心吟唱到了例如AOP的动态代理,但是这块记忆的非常不熟,结果磕磕绊绊&nbsp;]4.项目我看你写了AOP和注解,具体怎么实现滑动窗口限流的[&nbsp;梦到什么说什么,吟唱八股发散千万不要散到自己不熟悉的区域&nbsp;]5.也讲讲为什么另一个项目选择令牌桶,具体流程6.&nbsp;OK,讲讲&nbsp;Redis&nbsp;的数据类型?还有吗?就了解这五种嘛[&nbsp;把5个的基础类型从应用对比到历届底层全都吟唱了一遍。一句还有吗直接没力气了,简历就写了理解5种,别的我是真一点没看TT&nbsp;]7.讲讲Redission分布式锁实现8.这个指数退避怎么实现的9.在这里有考虑去保障幂等性嘛10.这里为什么使用指数退避呢?&nbsp;什么时候用均匀重传[已经晕过去了说不了解,刚说了后就意识到,估计应该说指数退避能缓解压力防止下游服务器雪崩之类的]11.ok,那讲讲JMM12.讲讲RocketMQ如何保证的不丢消息13.讲讲RocketMQ延迟消息原理14.讲讲项目Redis实现会话记忆这一块15.如果ai调用function&nbsp;calling出现幻觉,有考虑怎么解决吗?[&nbsp;不了解,面试官说什么接口幂等化,高危操作人工防护,没在听,感觉人已经飞升了TT&nbsp;]16.mcp了解嘛?和function&nbsp;calling有什么区别[&nbsp;依旧不了解,只能说了个前者规范架构抽象解耦,后者耦合高只能算个工具调用]17.AI生成代码的代码质量怎么保障,那平时如何review的呢18.算法。lc215&nbsp;&nbsp;数组中最大第k个元素19.打算考研还是本科就业20.反问1️⃣有哪里不足,有哪些需要提高的部分。[主要说知识广度不够,多刷算法,让我别太紧张]2️⃣部门业务会做什么人生第二次面试。感觉大厂面试官的气场压力很大应该凉了不过这次面试非常锻炼心态,多面试,多面试。
冰炸橙汁_不做oj版:redis除了五种基本数据类型,其他的几种还是要掌握一下的,挺常用
点赞 评论 收藏
分享
刚刷到字节跳动官方发的消息,确实被这波阵仗吓了一跳。在大家还在纠结今年行情是不是又“寒冬”的时候,字节直接甩出了史上规模最大的转正实习计划——ByteIntern。咱们直接看几个最硬的数,别被花里胡哨的宣传词绕晕了。首先是“量大”。全球招7000多人是什么概念?这几乎是把很多中型互联网公司的总人数都给招进来了。最关键的是,这次的资源分配非常精准:研发岗给了4800多个Offer,占比直接超过六成。说白了,字节今年还是要死磕技术,尤其是产品和AI领域,这对于咱们写代码的同学来说,绝对是今年最厚的一块肥肉。其次是大家最关心的“转正率”。官方直接白纸黑字写了:整体转正率超过50%。这意味着只要你进去了,不划水、正常干,每两个人里就有一个能直接拿校招Offer。对于2027届(2026年9月到2027年8月毕业)的同学来说,这不仅是实习,这简直就是通往大厂的快捷通道。不过,我也得泼盆冷水。坑位多,不代表门槛低。字节的实习面试出了名的爱考算法和工程实操,尤其是今年重点倾斜AI方向,如果你简历里有和AI相关的项目,优势还是有的。而且,转正率50%也意味着剩下那50%的人是陪跑的,进去之后的考核压力肯定不小。一句话总结:&nbsp;27届的兄弟们,别犹豫了。今年字节这是铁了心要抢提前批的人才,现在投递就是占坑。与其等到明年秋招去千军万马挤独木桥,不如现在进去先占个工位,把转正名额攥在手里。
喵_coding:别逗了 50%转正率 仔细想想 就是转正与不转正
字节7000实习来了,你...
点赞 评论 收藏
分享
评论
85
24
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务