从两种遍历结果构造二叉树
根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
思路:
两道题目思路都是相同的,从前序/后序遍历的结果中可以率先确定root,然后在中序遍历的结果中找到root,对左右子树进行划分,整个代码用递归的方式构造出二叉树。
105代码:
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
return bulid(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);//这个先写,你传入的参数肯定就是这几个
}
public TreeNode bulid(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd){
//最后写递归出口 base case,很简单,就是两个数组之一越界就是出口(其实写1个也行,因为两个数组长度肯定相同的)
if(preStart > preEnd || inStart > inEnd){
return null;
}
/*先序遍历框架-根、左、右*/
//1.先构造根节点的值,做根节点
//2.递归构造左子树
//3.递归构造右子树
//1.很明显根节点的值由先序遍历数组的第一个值确定
int rootVal = preorder[preStart];
TreeNode root = new TreeNode(rootVal);
//2.递归构造左子树
// root.left = bulid(preorder, ?, ?, inorder, ?, ?);//?需要我们画图去求的,也就是左右子树的索引
// root.right = bulid(preorder, ?, ?, inorder, ?, ?);//?需要我们画图去求的,也就是左右子树的索引
//首先通过rootVal在inorder中的索引(index),然后就能够知道inorder中左子树和右子树的边界
//可以改进的,一开始用hashMap把inorder的值和索引存好,到时候直接查就行。
int index = -1;
for(int i = inStart; i <= inEnd; i++){
if(rootVal == inorder[i]){
index = i;
break;
}
}
//找到了index,确定inorder中左右子树的边界
// root.left = bulid(preorder, ?, ?, inorder, inStart, index - 1);//确定inorder中左子树的边界
// root.right = bulid(preorder, ?, ?, inorder, index + 1, inEnd);//确定inorder中右子树的边界
//通过inorder中左子树节点的数目来确定preorder中左右子树的边界
int nums_of_left_tree = index - inStart;
// root.left = bulid(preorder, preStart + 1, preStart + nums_of_left_tree, inorder, ?, ?);//确定preorder中左子树的边界
// root.right = bulid(preorder, preStart + nums_of_left_tree + 1, preEnd, inorder, ?, ?);//确定preorder中右子树的边界
//最终确认好preorder和inorder中的左右子树边界
root.left = bulid(preorder, preStart + 1, preStart + nums_of_left_tree, inorder, inStart, index - 1);
root.right = bulid(preorder, preStart + nums_of_left_tree + 1, preEnd, inorder, index + 1, inEnd);
return root;
}
}
106代码:
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
int len=inorder.length;
return buildTree(inorder,0,len-1,postorder,0,len-1);
}
public TreeNode buildTree(int[] inorder,int inStart,int inEnd,int[] postorder,int postStart,int postEnd){
if(inStart>inEnd||postStart>postEnd){
return null;
}
//后序遍历的最后一个节点是根节点
int root = postorder[postEnd];
TreeNode node =new TreeNode(root);
//通过后序遍历中确定的根节点在中序遍历中确定左右子树的范围
int index=0;
for(int i=inStart;i<=inEnd;i++){
if(inorder[i]==root){
index=i;
break;
}
}
node.left=buildTree(inorder,inStart,index-1,postorder,postStart,postStart+index-inStart-1);
node.right=buildTree(inorder,index+1,inEnd,postorder,postEnd-inEnd+index,postEnd-1);
return node;
}
}