【一天一大 lee】从中序与后序遍历序列构造二叉树 (难度:中等)-Day20200925
时间:2022-07-26
本文章向大家介绍【一天一大 lee】从中序与后序遍历序列构造二叉树 (难度:中等)-Day20200925,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
题目:[1]
根据一棵树的中序遍历与后序遍历构造二叉树。
注意:你可以假设树中没有重复的元素。
例如,给出:
中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]
返回如下的二叉树:
3
/
9 20
/
15 7
抛砖引玉
思路
参数:
- 中序遍历的数组
- 后续遍历的数组
思路
- 借助后续遍历的节点找到每层子树的根节点
- rootIndex:二叉子树在后续遍历数组中的位置索引
- leftIndex:二叉子树的左子树在后续遍历数组中的位置索引
- rightIndex:二叉子树的右子树在后续遍历数组中的位置索引
查找根节点,及当前根节点左右子节点的逻辑:
- 后序遍历数组倒序遍历依次作为根节点
- 当前根节点的的左右子节点从中序遍历数组中查找:
- 这个节点的左节点在中序遍历数组中这个元素的前一位
- 这个节点的右节点在中序遍历数组中这个元素的后一位
深度优先搜索(DFS)
递归参数:
- 左子树根节点在 postorder 中的索引
- 右子树根节点在 postorder 中的索引
终止条件:
因为后续遍历是先遍历左子树再遍历右子树最后遍历根节点, 那么右子树的索引一定大于左子树的索引,当不满足是说明节点遍历完成,终止递归
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {number[]} inorder 中序遍历
* @param {number[]} postorder 后序遍历
* @return {TreeNode}
*/
var buildTree = function(inorder, postorder) {
let rootIndex = postorder.length - 1,
map = new Map()
// 记录在中序遍历数组中每个节点的位置,方便在得到根节点时查找左右子树节点
for (let i = 0; i < inorder.length; i++) {
map.set(inorder[i], i)
}
function dfs(leftIndex, rightIndex) {
if (leftIndex > rightIndex) return null
let root = new TreeNode(postorder[rootIndex]),
i = map.get(postorder[rootIndex])
rootIndex--
root.right = dfs(i + 1, rightIndex)
root.left = dfs(leftIndex, i - 1)
return root
}
return dfs(0, inorder.length - 1)
}
迭代
倒序遍历中序遍历数组(inorder):
- 二叉树的遍历逻辑变成了:先遍历右孩子,再遍历根节点,最后遍历左孩子
倒序遍历后序遍历数组(postorder):
- 二叉树的遍历逻辑变成了:先遍历根节点,再遍历右孩子,最后遍历左孩子
那么,倒序遍历后序遍历数组数组时,两个相邻的节点[a,b],两个节点在二叉树中的关系:
- b 是 a 的右子树上的节点
- a 没有右子树,并且 b 是与 a 子树相连的的左子树上的节点
实现
- postorder 中最后一个元素是整个二叉树的根节点
- 倒序遍历 postorder,inorder:
- inorder 中先遇到右子树上的节点:
- 不等于上一个生成子树的节点,则说明是上一个子树的右节点即情况 1,生成子树追击到上一个子树的 right 上
- 等于上一个生成子树的节点,则说明在 inorder 中遍历到了根节点,即情况 2,那么 inorder 继续遍历先遇到的应该是这个根节点对应子树的左节点
var buildTree = function(inorder, postorder) {
let rootIndex = postorder.length - 1,
root = new TreeNode(postorder[rootIndex]),
// 维护下一次遍历追击子树的最新子树
queue = [root],
inorderIndex = inorder.length - 1
rootIndex--
while (rootIndex >= 0) {
let node = queue[queue.length - 1],
nodeVal = postorder[rootIndex]
// 不等于上一个生成子树的节点,则说明是上一个子树的右节点
if (node.val !== inorder[inorderIndex]) {
node.right = new TreeNode(nodeVal)
queue.push(node.right)
} else {
// 维护inorder的倒序遍历索引跳过已经生成树的根节点
while (
queue.length &&
queue[queue.length - 1].val === inorder[inorderIndex]
) {
node = queue.pop()
inorderIndex--
}
// 情况 2
node.left = new TreeNode(nodeVal)
queue.push(node.left)
}
rootIndex--
}
return root
}
- 【译】《Understanding ECMAScript6》- 第五章-Class
- 【译】《Understanding ECMAScript6》- 第三章-Object
- 【译】《Understanding ECMAScript6》- 第二章-函数
- 【译】《Understanding ECMAScript6》- 第一章-基础知识(二)
- 【译】《Understanding ECMAScript6》- 第一章-基础知识(一)
- 聊聊C10K问题及解决方案
- 【译】《Understanding ECMAScript6》- 简介
- 深入理解 Java 并发之 synchronized 实现原理
- 你真的很熟分布式和事务吗?
- 基于Nginx负载均衡方案
- Android 使用android-support-multidex解决Dex超出方法数的限制问题
- Netty 实现原理浅析
- 上海2017QCon个人分享总结
- 为最佳性能调优 Nginx
- 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 数组属性和方法
- 设计模式 之 抽象工厂模式
- Angular应用里HTTP请求的错误处理
- 使用npm安装TypeScript
- TypeScript的interface关键字
- TypeScript的class关键字
- TypeScript里一些特殊的类型
- TypeScript的类型断言,有点像ABAP的强制类型转换
- 什么是TypeScript的字符串索引签名
- [初探] proxy 的优势与使用场景
- TypeScript里的interface和class以及对应的JavaScript代码
- TypeScript里的interface扩展,多继承以及对应的JavaScript代码
- TypeScript里的混合类型
- 完全图解 HTTPS
- TypeScript里的完整函数定义语法
- TypeScript里的类型为any和泛型的区别