「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战」。
题目
链接:leetcode-cn.com/problems/co…
给定两个整数数组 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 <= preorder.length <= 3000inorder.length == preorder.length-3000 <= preorder[i], inorder[i] <= 3000preorder和inorder均 无重复 元素inorder均出现在preorderpreorder保证 为二叉树的前序遍历序列inorder保证 为二叉树的中序遍历序列
思路
从前序和中序中寻找到二叉树结构
方法:递归,从最顶层树节点开始,可以发现每个node.val=当前的值,left=get左侧子树的最顶层节点,right=右侧子树的最顶层节点,可以依次递归下去;
思路:
可以通过观察树的结构特点,可以发现,树的顶点永远在前序的第一个元素,而找到这个顶点在中序数组中的位置,可以发现,树的左侧子树对应的数值
永远在中序数组的左边,右侧的子树的值永远在中序数组对应顶点的右边,那么我们就可以找到左侧子树的中序和前序数组,进入下一个递归,同样右侧子树的中序和前序
代码
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {number[]} preorder
* @param {number[]} inorder
* @return {TreeNode}
*/
var buildTree = function(preorder, inorder) {
var i = 0, tree = new TreeNode, treemap = {}, premap = {},inMap = {}, l = inorder.length;
while (i < l) {
premap[preorder[i]] = i;
inMap[inorder[i]] = i;
i++;
}
if(l ==0) return null;
function getTop (i0,i1,j0,j1) {
if(i0<0 || i1<0||j0>=l||j1>=l || i0>j0|| i1>j1) {
return null;
}
var val = preorder[i0];
var tree = new TreeNode(val);
var left0 = i0+1, left1 = inMap[val] - 1;
var l1 = j1 - inMap[val];
tree.left = getTop(i0+1, i1,i0+1 + left1 - i1, left1);
tree.right = getTop(j0 - l1 + 1, inMap[val] + 1, j0, j1);
return tree;
}
return getTop(0,0,l -1, l-1);
};
其他思路
- 前序遍历,根->左->右,中序遍历左->根->右。
- 即前序遍历为先找根节点,再遍历左节点,然后遍历右节点。中序遍历先遍历左节点,然后根节点,最后遍历右节点。
- 以题中例子为例,preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]。
- 根节点为preorder[0] = 3; inorder中inorder[1] = 3;所以inorder中 i < 1的都为左节点,i > 1的都为右节点。
- 那么可得左节点个数为 i - 0 = i,右节点个数为inorder.length - i - 1。
- 根据以上结果,我们可以获得preorder中,1 ~ i为左节点,i ~ inorder.length为右节点。
根据这个规律,我们可以分割二叉树,将问题转为分别找左子树和右子树的根结点。
var buildTree = function(preorder, inorder) {
if(preorder.length === 0 || inorder.length === 0) {
return null;
}
// 根据前序数组的第一个元素,就可以确定根节点
const root = new TreeNode(preorder[0]);
for(let i = 0;i < preorder.length; i++) {
// 用preorder[0]去中序数组中查找对应的元素
if(preorder[0] == inorder[i]) {
// 将前序数组分成左右两半
const pre_left = preorder.slice(1, i + 1);
const pre_right = preorder.slice(i + 1, preorder.length);
// 将中序数组分成左右两半
const in_left = inorder.slice(0, i);
const in_right = inorder.slice(i + 1, inorder.length);
// 之后递归的处理前序数组的左边部分和中序数组的左边部分
root.left = buildTree(pre_left,in_left);
// 递归处理前序数组右边部分和中序数组右边部分
root.right = buildTree(pre_right,in_right);
break;
}
}
return root;
};