【LeetCode】重建二叉树day04
时间:2022-07-23
本文章向大家介绍【LeetCode】重建二叉树day04,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
题目
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/
9 20
/
15 7
限制:
0 <= 节点个数 <= 5000
解题思路
- 二叉树的特点是什么?
- 每个节点最多有两棵子树,所以二叉树中不存在度大于2的节点。也可以没有左子树和右子树。
2.根据便利的特点来进行重建
- 前序遍历: 二叉树为空,则空操作返回,否则访问根节点,然后前序遍历左子树,再前序遍历右子树。这块就得注意了这就是插入点。
- 中序便利: 若树为空,则空操作返回,否则从根节点开始,中序遍历根节点的左子树,然后访问根节点,然后访问右子树。
3.通过回想这个两个遍历的特点,那开始重建
4.从中序便利中我们可以判断出根节点是哪一个,那就是前序遍历的preorder[0].
5.我们知道了根节点,哪我们可以根据中续遍历,就可以得出左子树和右子树。有哪些元素。
6.由于树中的节点数量与遍历方式无关,通过中序遍历得知左子树和右子树的节点数量之后,可以根据节点数量得到前序遍历中的左子树和右子树的分界,因此可以进一步得到左子树和右子树各自的前序遍历和中序遍历,可以通过递归的方式,重建左子树和右子树,然后重建整个二叉树。
代码
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
//如果前序遍历数组为空那这棵树也是空的
if(preorder == null ){
return null ;
}else{
//先拿到中序便利的数量
int length = inorder.length;
//通过Map记录中序遍历的值,在后面可以根据根节点拿到左子树和又字树的元素
Map<Integer,Integer> inorderMap = new HashMap<Integer,Integer>();
for(int i = 0 ;i<length;i++){
inorderMap.put(inorder[i],i);
}
// 构建一个树根据前序遍历和后续遍历的数组
//其实有人会问为什么要这样写这么多参数。因为我们要递归调用将其中的遍历的数组切开,然后去便利左子树右子树。
return buildTree(preorder,0,length-1,inorder,0,length-1,inorderMap);
}
}
public TreeNode buildTree(int [] preorder,int preorderStart,int preorderEnd,int[] inorder,int inoderStart, int inorderEnd,Map<Integer,Integer> inorderMap){
if(preorderStart>preorderEnd){
return null;
}
// 拿到根节点
int rootVal = preorder[preorderStart];
// 创建一颗有根节点的二叉树
TreeNode root = new TreeNode(rootVal);
if(preorderStart == preorderEnd){
return root;
}else{
拿到根节点在遍历数组中的位置
int rootIndex = inorderMap.get(rootVal);
// 左子树的节点数量
int leftNodes = rootIndex - inoderStart; 右子树节点的数量
int rightNodes = inorderEnd - rootIndex;
构建左子树
TreeNode leftSubtree = buildTree(preorder, preorderStart + 1, preorderStart + leftNodes, inorder, inoderStart, rootIndex - 1, inorderMap);
便利右子树
TreeNode rightSubtree = buildTree(preorder, preorderEnd - rightNodes + 1, preorderEnd, inorder, rootIndex + 1, inorderEnd, inorderMap);
//将左子树与右子树拼起来
root.left = leftSubtree;
root.right = rightSubtree;
}
return root;
}
}
总结
- 刚开始做这道题真的没有思路,于是就看一边答案,然后尝试自己慢慢去写,然后几经调试。就跑出来了。
- 核心思想就是中序遍历和前序遍历的算法。
- 还有就是理解左子树和右子树的便利过程
参考
- https://blog.csdn.net/My_Jobs/article/details/43451187
- https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/
- ASM 翻译系列第十八弹:ASM Internal ASM file number 5
- 菜单式Shell运维脚本调试小记
- 优化Postgres-x2 GTM
- 启用某些Linux发行版的root帐号
- Linux中的完美截图工具:Deepin-ScreenShot
- ASM 翻译系列第二十弹:ASM Internal ASM file number 7
- Linux:awk命令详解
- 给已安装的Linux新增Swap交换分区
- ASM 翻译系列第二十一弹:ASM Attributes Directory
- Linux:sed命令详解
- ASM 翻译系列第二十二弹:ASM Internal ASM file number 8
- Ghost安装Win7/XP后自动恢复IP的批处理
- ASM 翻译系列第二十三弹:ASM Internal ASM files number 12 and 254
- Shell脚本的简单排错法及调试程序bashdb
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- ES的新特性
- PHP设计模式|观察者模式
- JavaScript 中 this 的错误认识、绑定规则、常见问题讲解
- 实践:SpringBoot实现定时任务的动态增删启停
- Java并发编程的艺术[3]
- R语言 | 根据数据框的顺序进行筛选
- 上帝视角看 TypeScript
- 一文 get 入门 canvas 的最佳路径
- Matlab系列之数组的基本操作
- Matlab系列之数组(矩阵)的生成
- R语言T检验的简单小例子
- ggplot2 修改图例的一些操作
- 实践:SpringBoot实现定时任务的动态增删启停
- Asp.Net Core API 需要认证时发生重定向的解决方法
- 在 Windows 系统上启用远程应用