题目
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历数组 preorder = [3,9,20,15,7]
中序遍历数组 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
限制:
0 <= 节点个数 <= 5000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof
经验总结
- 二叉树的问题一般都是分治思想,递归去做。因为二叉树本身就是递归定义的。
- 首先前序/后序遍历 + 中序遍历可以重建二叉树。前序+中序来重建二叉树与后序+中序的思路是类似的。
题目分析
题目分析引用自作者:jyd
- 前序遍历特点: 节点按照 [ 根节点 | 左子树 | 右子树 ] 排序
- 以题目示例为例:[ 3 | 9 | 20 15 7 ]
- 中序遍历特点: 节点按照 [ 左子树 | 根节点 | 右子树 ] 排序
- 以题目示例为例:[ 9 | 3 | 15 20 7 ]
- 根据题目描述输入的前序遍历和中序遍历的结果中都不含重复的数字,说明树中每个节点值都是唯一的。
解题思路
解题思路引用自作者:liweiwei1419
- 前序遍历的第 1 个结点一定是二叉树的根结点
- 在中序遍历中,根结点把中序遍历序列分成了两个部分
- 左边部分构成了二叉树的根结点的左子树
- 右边部分构成了二叉树的根结点的右子树
- 查找根结点在中序遍历序列中的位置,可以遍历,也可以在一开始就记录下来。
举例说明
如有二叉树如下
1
/ \
2 3
/ \
4 5
- 因为前序遍历数组的第一个元素就是当前二叉树的根节点。
- 那么在中序遍历数组种找到这个元素,就可以将中序遍历分成 2 个部分。
- 在以上面的例子,中序遍历就被分成了 4 2 5 和 3 两个部分。
- 4 2 5就是左子树,
- 3就是右子树。
- 最后,根据左右子树,继续递归即可。
引用自作者:xin-tan
代码
–执行用时:8 ms --内存消耗:3.9 MB
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func buildTree(preorder []int, inorder []int) *TreeNode {
if len(preorder)==0{
return nil
}
loc:=seachRoot(preorder[0],inorder)
return &TreeNode{preorder[0],buildTree(preorder[1:loc+1],inorder[:loc]),buildTree(preorder[loc+1:],inorder[loc+1:]),}
}
func seachRoot(root int,inorder []int)int{
for i,v:=range inorder{
if v==root{
return i
}
}
return -1
}
优化写法
–执行用时:4 ms --内存消耗:4 MB
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func buildTree(preorder []int, inorder []int) *TreeNode {
if preorder==nil || len(preorder)==0{
return nil
}
tree:=&TreeNode{
preorder[0],
nil,
nil,
}
if len(preorder)==1{
return tree
}
root:=seachRoot(preorder[0],inorder)
switch root{
case 0:
tree.Left=nil
case 1:
tree.Left=buildTree([]int{preorder[root]},inorder[:root])
default:
tree.Left=buildTree(preorder[1:root+1],inorder[:root])
}
if root == len(inorder) {
tree.Right = &TreeNode{Val:preorder[root+1]}
} else {
tree.Right = buildTree(preorder[root+1:], inorder[root+1:])
}
return tree
}
func seachRoot(root int,inorder []int)int{
for i,v:=range inorder{
if v==root{
return i
}
}
return -1
}