【牛客 - 剑指offer】JZ7 重建二叉树 Java实现 两种方案(递归+非递归stack)

news/2024/5/6 8:14:37/文章来源:https://blog.csdn.net/guliguliguliguli/article/details/126900632

文章目录

  • 剑指offer题解汇总 Java实现
  • 本题链接
  • 题目
  • 方案一 递归
  • 方案二 非递归 用栈实现


剑指offer题解汇总 Java实现

https://blog.csdn.net/guliguliguliguli/article/details/126089434

本题链接

知识分类篇 - 树 - JZ7 重建二叉树

题目

在这里插入图片描述
题目的主要信息

  • 根据二叉树的前序和中序遍历序列,重建该二叉树,并返回根节点

  • 两个遍历都没有重复的元素

方案一 递归

递归是一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。因此递归过程,最重要的就是查看能不能将原本的问题分解为更小的子问题,这是使用递归的关键。

而二叉树的递归,则是将某个节点的左子树、右子树看成一棵完整的树,那么对于子树的访问或者操作就是对于原树的访问或者操作的子问题,因此可以自我调用函数不断进入子树。

对于二叉树的前序遍历,第一个元素必定是二叉树的根节点,因为序列没有重复的元素,因此,中序遍历中可以找到相同的这个元素,并且中序遍历顺序中,根节点将将二叉树分为左右子树两部分

例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},
首先看前序遍历,1是根节点
在中序遍历中查找1的位置,1左边的都在根节点的左子树,即{4,7,2}在左子树;1右边的都在根节点的右子树,即{5,3,8,6}在右子树
前序遍历中也分为了{2,4,7}和{3,5,6,8}
2位于这个前序遍历中子集的第一位,说明2是左子树的根节点
在{4,7,2}这一中序遍历中,{4,7}都在2的左边,即{4,7}都是以2为根的左子树上的节点
3位于这个前序遍历中子集的第一位,说明3是右子树的根节点
在{5,3,8,6}这一中序遍历中,5位于3的左边,{8,6}位于3的右边,说明,5是3的左子节点,{8,6}都位于3的右子树

按照这种思路,依次类推可以得到二叉树的结构如下图
在这里插入图片描述

具体做法

  1. 先根据前序遍历第一个点建立根节点

  2. 然后遍历中序遍历找到根节点在数组中的位置

  3. 再按照子树的节点数,将两个遍历序列分割成子数组,将子数组送入函数建立子树

  4. 直到子树的序列长度为0,结束递归

import java.util.*;/*** Definition for binary tree* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val = x; }* }*/
public class Solution {public TreeNode reConstructBinaryTree(int[] pre, int[] vin) {int preLength = pre.length;int vinLength = vin.length;if (preLength == 0 || vinLength == 0) {return null;}//构建根节点TreeNode root = new TreeNode(pre[0]);for (int i = 0; i < vin.length; i++) {//在中序遍历中找到pre[0]if (vin[i] == pre[0]) {//Arrays.copyOfRange(arr,from,to)//[from,to)//构建左子树root.left = reConstructBinaryTree(Arrays.copyOfRange(pre, 1, i + 1), Arrays.copyOfRange(vin, 0, i));//构建右子树root.right = reConstructBinaryTree(Arrays.copyOfRange(pre, i + 1, preLength), Arrays.copyOfRange(vin, i + 1, vinLength));break;}}return root;}
}

方案二 非递归 用栈实现

栈,是一种仅支持在表尾进行插入和删除操作的线性表,这一端被称为栈顶,另一端被称为栈底

  • 元素入栈指的是把新元素放到栈顶元素的上面,使之成为新的栈顶元素

  • 元素出栈指的是从一个栈删除元素又称作出栈或退栈,他是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素

思路

除了递归, 我们可以使用类似非递归前序遍历的方式建立二叉树,利用栈辅助进行非递归,然后依次建立节点。

具体做法

  1. 首先前序遍历第一个数组依然是根节点,并建立栈辅助遍历

  2. 开始判断,前序遍历中相邻的两个数字有以下几种可能的情况:

    • 前序遍历中后一个节点是前一个节点的左子节点

    • 前序遍历中后一个节点是前一个节点的右子节点

    • 前序遍历中后一个节点是前一个节点的祖先的右子节点

  3. 同时遍历pre和vin,判断是否是左子节点

    • 如果是左子节点,则不断深入,用栈记录祖先

    • 如果不是左子节点,需要弹出栈回到相应的祖先,然后进入右子树,整个过程类似非递归前序遍历

自己的一些理解

  1. for循环中i指向的节点,表示为当前节点
  2. cur变量用来存储当前节点的上一个节点
  3. cur之前的父节点、祖先节点都存放在stack中
  4. 如果vin[j]和cur不一样,则说明,i节点是cur的左子节点
  5. 如果vin[j]和cur一样,表示cur已经是最左下的一个节点,i指向的节点可能是cur或者是cur祖先的右子节点
  6. cur和vin[j]一样,j向后移动一个位置,再看vin[j]和栈顶元素是否相等
    • 如果不等,则说明i指向的节点是cur的右子节点
    • 如果相等,弹出栈顶元素,并把cur赋值为栈顶元素,再次比较,看新的栈顶元素是否与vin[j]相同,如果不等,i指向的节点就是cur的右子节点,如果相等,继续while循环…
import java.util.*;
public class Solution {public TreeNode reConstructBinaryTree(int [] pre,int [] vin) {int n = pre.length;int m = vin.length;//每个遍历都不能为0if(n == 0 || m == 0)return null;Stack<TreeNode> s = new Stack<>();//首先建立前序第一个即根节点TreeNode root = new TreeNode(pre[0]);TreeNode cur = root;for(int i = 1, j = 0; i < n; i++){//要么旁边这个是它的左节点//没有和vin[j]相等说明,还没有深入到最左下节点//判断是否是左子节点,如果是左子节点,则不断深度,用栈记录祖先if(cur.val != vin[j]){cur.left = new TreeNode(pre[i]);s.push(cur);//要么旁边这个是它的右节点,或者祖先的右节点cur = cur.left;}else{//如果不是左子节点,则需要弹出栈回到相应的祖先,然后进入右子树//j++的操作,跳过了根节点j++;//弹出到符合的祖先while(!s.isEmpty() && s.peek().val == vin[j]){cur = s.pop();j++;}//添加右节点cur.right = new TreeNode(pre[i]);cur = cur.right;}}return root;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_11341.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机组成原理笔记(王道考研) 第一章:计算机系统概述

内容基于中国大学MOOC的2023考研计算机组成原理课程所做的笔记。 感谢LY&#xff0c;他帮我做了一部分笔记。由于听的时间不一样&#xff0c;第四章前的内容看起来可能稍显啰嗦&#xff0c;后面会记得简略一些。 西电的计算机组织与体系结构课讲法和王道考研的课不太一样&…

Affinity Propagation (AP)近邻传播聚类

近邻传播聚类&#xff1a;根据 N 个数据点之间的相似度聚类&#xff0c;相似度可以是对称的&#xff0c;即两个数据点互相之间的相似度一样(如欧氏距离)&#xff1b;也可以是不对称的&#xff0c;即两个数据点互相之间的相似度不等。这些相似度组成 NN 的相似度矩阵 S (N代表N个…

IP静态路由

IP静态路由基础概述 为了实现数据的转发,路由器必须有能力建立、刷新路由表,并根据路由表转发数据包 定义 路由是数据通信网络中的最基本的要素。路由信息就是知道报文发送的路径信息,路由的过程就是报文中继转发的过程 目的 为了实现数据的转发,路由器、路由表和路由协议是…

selenium工具之find_element(by=By.xx, value=xxx) find_elements(by=By.xx, value=xxx)详解

前言 selenium是一款十分强大的Web应用自动化框架,我们可以通过它来自动操控浏览器。操控浏览器的实质是操控浏览器的界面元素,因此定位元素是使用selenium的关键,selenium中通过 find_element() 方法来完成定位。 用法 1、通过webdriver对象的 find_element(by="属性名…

【教程】在 visual studio 共享和重用项目属性

环境 os&#xff1a;windows 10IDE&#xff1a;visual studio 2015 前言 在 visual studio 下开发项目时&#xff0c;通常会配置项目的属性&#xff0c;比如引入外部头文件&#xff0c;引入外部库之类的 尤其是不同的开发模式&#xff0c;debug 和 release&#xff0c;不同…

PHP+经贸时间轴 毕业设计-附源码211617

基于php经贸时间轴小程序 摘 要 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;经贸时间轴小程序被用户普遍使用…

Cache与内存映射

全相联 主存的某一Block可以映射到Cache中的任意一Block&#xff0c;多对多N<>M&#xff1b; 全相联地址格式&#xff1a; 高位为块地址与tag比较&#xff0c;offset负责取出Block内的字节 放一道例题把&#xff1a; 既然新开了一章写就写的细一点&#xff0c;Cache全…

深度学习入门:基于Python的理论与实现

1.Python入门 python中使用class关键字来定义类&#xff1a; class 类名&#xff1a;def __init__(self, 参数,...):#构造函数...def 方法1(self, 参数, ...): # 方法1...def 方法2(self, 参数, ...): # 方法2...这里有一股特殊的__init__方法&#xff0c;这是进行初始化的方…

合成/聚合复用原则

合成/聚合复用原则 很多情况继承会带来麻烦:对象的继承关系是在编译时就定义好了,所以无法在运行时改变从父类继承的实现。子类的实现与它的父类有非常密切的依赖关系,以至于父类实现中的任何变化必然会导致子类发生变化。当需要复用子类时,如果继承下来的实现不适合解决新…

港科夜闻|香港科大为庆祝建校30周年举办慈善义卖,限量推出一批具有收藏价值的非同质化代币(NFT)艺术精品...

关注并星标每周阅读港科夜闻建立新视野 开启新思维1、香港科大为庆祝建校30周年举办慈善义卖&#xff0c;限量推出一批具有收藏价值的非同质化代币(NFT)艺术精品。这系列NFT艺术收藏品的亮点&#xff0c;就是26款按英文字母A至Z排列、重现香港科大生活点滴的原创数码图像&#…

【计算机网络】第五章 传输层

第五章 传输层 一、传输层概述 传输层功能 协议&#xff1a;TCP和UDP 是只有主机才有的层次 功能&#xff1a; 提供进程和进程之间的通信&#xff0c;网络层提供的是主机之间的通信复用和分用&#xff1a;将数个进程的信息复用起来&#xff0c;发送出去&#xff1b;收到信息…

安装 Windows Server 2019 VM虚拟机

目录&#xff08;1&#xff09;系统语言设置&#xff08;2&#xff09;点击【Install now】&#xff08;3&#xff09;激活Windows&#xff08;4&#xff09;选择安装版本&#xff08;5&#xff09;同意【license terms】&#xff08;6&#xff09;选择安装类型&#xff08;7&a…

新华三学习记录

文章目录前言计算机网络基础基本概念TCP/IP四层和OSI七层模型LAN/WAN冲突域基本组网基本协议总结前言 本博客仅做学习笔记&#xff0c;如有侵权&#xff0c;联系后即刻更改 科普&#xff1a; 计算机网络基础 参考文章 基本概念 计算机网络 分布各地的具有独立功能的计算机…

【云原生-Docker】Docker 安装 MySQL

&#x1f341;博客主页&#xff1a;&#x1f449;不会压弯的小飞侠 ✨欢迎关注&#xff1a;&#x1f449;点赞&#x1f44d;收藏⭐留言✒ ✨系列专栏&#xff1a;&#x1f449;Docker学习专栏 ✨学习社区&#xff1a;&#x1f449;不会压弯的小飞侠 ✨知足上进&#xff0c;不负…

5.Eureka服务注册的源码分析(springcloud)

一、Eureka 概念的理解 1 服务的注册 当项目启动时&#xff08;eureka 的客户端&#xff09;&#xff0c;就会向 eureka-server 发送自己的元数据&#xff08;原始数据&#xff09;&#xff08;运行的 ip&#xff0c;端口 port&#xff0c;健康的状态监控等&#xff0c;因为使用…

P02 反射

P02 反射1.反射概述1.1 反射的基本作用1.2 反射的关键2.反射获取类对象2.1 forName(String className)2.2 类名.class2.3 对象.getClass()3.反射获取构造器对象![在这里插入图片描述](https://img-blog.csdnimg.cn/e234dd155af94a5c80223d64b112f4bf.png)3.1 Class 类中用于获取…

18.Composition API(四)高级语法补充

1.自定义指令 之前我们学习了各种指令&#xff1a;v-model、v-for、v-show等&#xff0c;除了这些指令外&#xff0c;Vue允许我们自定义指令。 什么时候使用自定义指令&#xff1f; 需要对DOM元素进行底层操作&#xff0c;这个时候就会用到自定义指令。 注意&#xff1a;在V…

第二章 ES数据操作与集群

一、回顾 1.介绍ES 2.ES原理 3.ES功能 4.ES使用场景 5.ES安装 1)ES配置文件(单点配置) [root@es01 ~]# grep ^[a-z] /etc/elasticsearch/elasticsearch.yml node.name: es-1 path.data: /data/es/data path.logs: /data/es/log bootstrap.memory_lock: true network.host: 1…

Android Gradle plugin requires Java 11 to run. You are currently using Java 1.8

因为另一台机器开发时,android studio提示更新什么东西,无脑点了。 导致原先的那台开发机器,无法build,报异常: Android Gradle plugin requires Java 11 to run. You are currently using Java 1.8 有两个方法解决: 1、修改jdk从1.8改到11如果没有这个选项,可能需要安装…

高项重点内容

BI&#xff0c;商业智能 联机事务处理OLTP主要是执行基本日常的事务处理&#xff0c;比如数据库记录的增删查改。比如在银行的一笔交易记录&#xff0c;就是一个典型的事务。联机分析处理是数据仓库系统的主要应用&#xff0c;支持复杂的分析操作&#xff0c;侧重决策支持&…