柿子带你刷 二叉树(leetcode实战篇)
二叉树实战
知识补充
(如果不是我这种对二叉树没什么概念的小菜鸡,直接到最底下去看看 [105]从前序与中序遍历序列构造二叉树的解题思路吧!)
在刷这道题之前,我们应该理解一下如何快速的从前序遍历、中序遍历、后序遍历【1】
- 前序遍历:
- 前序遍历的遍历方式呢:根、左、右(根节点、和他的左右节点)
- 中序遍历:
- 中序遍历的遍历方式呢:左、根、右
- 后序遍历:
- 中序遍历的遍历方式呢:左、右、根
根据这个规则我们利用下面的这个例子简单的来做一个练习:
根据下面的二叉树,快速进行前序、后序、中序的序列遍历吧:
- 前序(根、左、右):A B C D E F G H I
- 中序(左、根、右):C B D A G F H E I
- 后序(左、右、根):C D B G H F I E A
实战
光说不练假把式,说了这么多,没有用js实现都是纸上谈兵
二叉树的构造函数
function TreeNode(val, left, right) {
this.val = (val===undefined ? 0 : val)
this.left = (left===undefined ? null : left)
this.right = (right===undefined ? null : right)
}
前序遍历
给你二叉树的根节点
root
,返回它节点值的 前序 **遍历。
输入:root = [1,null,2,3] 输出:[1,2,3]
输入:root = [] 输出:[]
输入:root = [1] 输出:[1]
输入:root = [1,2] 输出:[1,2]
那么这道题的解题思路就很简单了
按照根-左-右的方式进行遍历就好
var preorderTraversal = function(root) {
const res = []
preorder(root, res)
return res
};
const preorder = (root, res) => {
if(root == null){
return
}
res.push(root.val)
preorder(root.left, res)
preorder(root.right, res)
}
中序遍历
给定一个二叉树的根节点
root
,返回 它的 中序 遍历 。
输入:root = [1,null,2,3] 输出:[1,3,2]
输入:root = [] 输出:[]
输入:root = [1] 输出:[1]
按照左、根、右的方式进行遍历就好
var inorderTraversal = function (root) {
const res = []
inorder(root, res)
return res
};
const inorder = (root, res) => {
if (root == null) {
return
}
inorder(root.left, res)
res.push(root.val)
inorder(root.right, res)
}
仔细一看代码有没有一种???似曾相识的感觉?
不错,我们就仅仅换了一个位置罢了!
后序遍历
一样我们记住公式和顺序,换汤不换药
按照 左、右、根
var postorderTraversal = function(root) {
const res = []
postorder(root, res)
return res
};
// 按照左、右、根的顺序来就好
const postorder = (root,res) => {
if(root === null){
return
}
postorder(root.left, res)
postorder(root.right, res)
res.push(root.val)
}
到这里我们的前中后遍历大家就都应该简单懂了吧!
接下来。。。。。重头戏上场!
从前序与中序遍历序列构造二叉树
给定两个整数数组 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:
输入: preorder = [-1], inorder = [-1]
输出: [-1]
思路
我们需要紧紧抓住前序遍历序列和中序遍历序列的定义
- 前序遍历序列的第一个元素就是树的根节点
- 前序遍历的节点元素的后面的元素 先是左子树的所有节点而后是右子树的所有节点
- 用示例 1举个例子**[3,9,20,15,7]**
- 3 是二叉树的根节点
- [9] 则是 二叉树的左子树的所有节点
- [20,15,7]是右子树的所有节点
- 用示例 1举个例子**[3,9,20,15,7]**
- 中序遍历中,根节点把中序遍历序列分成了两个部分,左边部分构成了二叉树的根节点的左子树,右边则是右子树
- 举示例 1个例子**[9,3,15,20,7]**
- 3 是二叉树的根节点
- [9] 则是 二叉树的左子树的所有节点
- [15,20,7]是右子树的所有节点
- 举示例 1个例子**[9,3,15,20,7]**
那我们的思路就有了:
- 我们可以根据当前前序遍历的第一个元素获取当前二叉树的根节点
- 利用二叉树的根节点 找到中序遍历的时候的位置,在中序遍历和前序遍历的时候,也就是节点的位置不同,但是左右节点的个数是相同的
- 这样我们就能确定他的左节点有多少,和右节点有多少个
- 这样我们就可以通过 parentIndex = inorder.indexOf(preorder[0]) 来获取切分左右节点的个数的位置
- 左节点:preorder.slice(1, parentIndex + 1)
- 右节点:preorder.slice(parentIndex + 1)
解法
var buildTree = function(preorder, inorder) {
if(inorder.length === 0 || preorder.length === 0){
return null
}
const res = new TreeNode(preorder[0])
const parentIndex = inorder.indexOf(preorder[0])
res.left = buildTree(preorder.slice(1, parentIndex + 1), inorder.slice(0, parentIndex))
res.right = buildTree(preorder.slice(parentIndex + 1), inorder.slice(parentIndex + 1))
return res
};
解析:
我们通过slice 每次就传入当前节点的左/右子节点元素的数组,所以我们可以确定,前序序列的数组的第一项肯定就是当前这个二叉树节点的根节点。
利用这个根节点我们通过查询中序序列的位置,我们可以得到这个根节点的左/右节点数组。
递归查询,即可
知识点归纳
【2】105. 从前序与中序遍历序列构造二叉树 Construct Binary Tree from Preorder and Inorder Traversal
优秀博文推荐
转载自:https://juejin.cn/post/7101685412069900301