1. 105.从前序与中序遍历序列构造二叉树
原题链接
根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
1.1. 要点
- 前序遍历的过程中,每次最先遇到的都可以将其视为子树的根结点。
- 对比一下前序遍历的数组preorder,不难发现
第一个数是二叉树的根结点
第二个数是左子树的根结点
第三个数是右子树的根结点
依次类推… - 知道这个特性之后,我们需要知道哪些元素应该在左边,哪些在右边。
- 你应该要能理解中序遍历inorder:根结点是在中间被遍历到的,也就是说在中序遍历过程中,根结点的左边数组为左子树元素而右边是右子树元素。
- 要做的事情就是确定根结点,之后确认子树的根结点。
将有序数组转换为二叉搜索树动画演示
1.2. 递归
1.2.1. 代码片段
func buildTree(preorder []int, inorder []int) *TreeNode {
if len(preorder) == 0 || len(inorder) == 0 {
return nil
}
var num = 0
return buildTreeHelper(preorder, inorder, &num)
}
func buildPos(inorder []int, val int) int {
var pos int
for i, v := range inorder {
if v == val {
pos = i
break
}
}
return pos
}
func buildTreeHelper(preorder []int, inorder []int, num *int) *TreeNode {
val := preorder[*num]
tree := &TreeNode{
Val: val,
}
pos := buildPos(inorder, val)
var left, right []int
if pos-1 >= 0 {
*num++
left = inorder[:pos]
tree.Left = buildTreeHelper(preorder, left, num)
}
if pos+1 < len(inorder) {
*num++
right = inorder[pos+1:]
tree.Right = buildTreeHelper(preorder, right, num)
}
return tree
}
代码解释
- 每一次取出一个根结点并创建子树。
- 递归创建左右子树,注意
num
是一个指针变量,因为在每一次递归过程中创建的节点都是唯一的,且每一次都是顺序往下拿,如果不是指针变量会导致重复创建结点。
2. 106.从中序与后序遍历序列构造二叉树
原题链接
根据一棵树的中序遍历与后序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
2.1. 要点
仔细分析一下后序遍历的数组postorder,翻转过来很像先序遍历,只不过现在变成先遍历右结点其次遍历左结点。
2.2. 递归
因为与105.从前序与中序遍历序列构造二叉树 解法基本一致,这里就不过多介绍了
2.2.1. 代码片段
func buildPos(inorder []int, val int) int {
var pos int
for i, v := range inorder {
if v == val {
pos = i
break
}
}
return pos
}
func buildTree(inorder []int, postorder []int) *TreeNode {
var num = 0
return buildTreeHelper(inorder, postorder, &num)
}
func buildTreeHelper(inorder []int, postorder []int, num *int) *TreeNode {
if len(inorder) == 0 {
return nil
}
val := postorder[len(postorder)-1-*num] //从尾往前取到根结点
tree := &TreeNode{
Val: val,
}
pos := buildPos(inorder, val)
if pos+1 < len(inorder) {
*num++
tree.Right = buildTreeHelper(inorder[pos+1:], postorder, num)//这里不同点是先构建右子树,因为下一次先取到的根结点在右边而不是左边。
}
if pos-1 >= 0 {
*num++
tree.Left = buildTreeHelper(inorder[:pos], postorder, num)
}
return tree
}