一、题目
给定一棵树的前序遍历 preorder
与中序遍历 inorder
。请构造二叉树并返回其根节点。
例如:preorder = [3,9,20,15,7], inorder = [9,3,15,20,7],得到如下二叉树。
1、分析
通过前序遍历和中序遍历构建二叉树的原理就不说了,都是基础。说说怎么用代码的方式构造二叉树。
一开始想到用队列能不能实现,发现写起来太复杂了,还是用递归+partition。
首先看前序遍历数组,第一个数就是当前需要构造的根节点【3】,于是在中序遍历数组中找到这个节点。于是就可以将中序遍历数组分为三部分:①左子树【9】②根结点【3】③右子树【15,20,7】。要得到左子树的根结点,递归查找左子树部分;得到右子树的根结点,递归查找右子树部分。当元素用完时,查找结束。
2、代码
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
return helper(preorder,0,preorder.length-1,inorder,0,inorder.length-1);
}
public TreeNode helper(int[] preorder,int preStart,int preEnd,int[] inorder,int inStart,int inEnd){
if(preStart > preEnd || inStart > inEnd) return null;
//当前根节点
TreeNode root = new TreeNode(preorder[preStart]);
//找到中序遍历中根结点的下标
int index = inStart;
for(int i = inStart; i <= inEnd; i++){
if(root.val == inorder[i]) index = i;
}
//求左子树长度
int leftChildLength = index - inStart;
//关键点在于划分好左右子树的下标范围
//递归求解左子树根结点
root.left = helper(preorder,preStart+1,preStart+leftChildLength,inorder,inStart,index-1);
//递归求解右子树根结点
root.right = helper(preorder,preStart+leftChildLength+1,preEnd,inorder,index+1,inEnd);
return root;
}
}
二、题目变形
从中序遍历与后序遍历序列中构造二叉树
原理是一样的,递归+partition,划分好左右子树的区间即可。
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
return helper(inorder,0,inorder.length-1,postorder,0,postorder.length-1);
}
public TreeNode helper(int[] inorder,int inStart,int inEnd,int[] postorder,int postStart,int postEnd){
if(inStart > inEnd || postEnd < postStart) return null;
TreeNode root = new TreeNode(postorder[postEnd]);
//找到右子树长度
int index = inEnd;
for(int i = inEnd; i >= inStart; i--){
if(inorder[i] == root.val) index = i;
}
int rightChildLength = inEnd - index;
root.right = helper(inorder,index+1,inEnd,postorder,postEnd-rightChildLength,postEnd-1);
root.left = helper(inorder,inStart,index-1,postorder,postStart,postEnd-rightChildLength-1);
return root;
}
}