【算法】重建二叉树(前+中、后+中)
(一)二叉树的重建
二叉树是非线性结构,每个结点会有零个、一个或两个孩子结点,一个二叉树的遍历序列不能决定一棵二叉树,但某些不同的遍历序列组合可以惟一确定一棵二叉树。
可以证明,给定一棵二叉树的前序遍历序列和中序遍历序列可以惟一确定一棵二叉树的结构,给定一棵二叉树的后序遍历序列和中序遍历序列也可以惟一确定一棵二叉树的结构。
注意:这还有一个条件:二叉树的任意两个结点的值都不相同。
算法如下:
-
用前序序列的第一个结点(后序序列的最后一个结点)作为根结点;
-
在中序序列中查找根结点的位置,并以此为界将中序序列划分为左、右两个序列(左、右子树);
-
根据左、右子树的中序序列中的结点个数,将前序序列(后序)去掉根结点后的序列划分为左、右两个序列,它们分别是左、右子树的前序(后序)序列;
-
对左、右子树的前序(后序)序列和中序序列递归地实施同样方法,直到所得左、右子树为空。
(二)根据前序和中序序列确定二叉树
参考题目:
LeetCode105、Construct Binary Tree from Preorder and Inorder Traversal
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder==null || inorder==null)
return null;
return buildTree(preorder,inorder,0,preorder.length-1,0,inorder.length-1);
}
public TreeNode buildTree(int[] preorder,int[]inorder,int pStart,int pend,int iStart,int iend){
if(pStart>pend || iStart>iend)
return null;
TreeNode root=new TreeNode(preorder[pStart]); //前序序列第一个为根
if(pStart==pend)
return root;
int mid=iStart;
while(mid<=iend && inorder[mid]!=root.val)
mid++;
//找到mid即为根在中序序列中的位置
int leftCount=mid-iStart;
//重建左子树和右子树
root.left=buildTree(preorder,inorder,pStart+1,pStart+leftCount,iStart,mid-1);
root.right=buildTree(preorder,inorder,pStart+leftCount+1,pend,mid+1,iend);
return root;
}
}
(三)根据后序和中序序列确定二叉树
参考题目:
LeetCode106、Construct Binary Tree from Inorder and Postorder Traversal
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
if(inorder==null || postorder==null)
return null;
return buildTree(inorder,postorder,0,inorder.length-1,0,postorder.length-1);
}
public TreeNode buildTree(int[] inorder,int[] postorder,int iStart,int iend,int pStart,int pend){
if(iStart>iend || pStart>pend)
return null;
//后续遍历序列的最后一个为根
TreeNode root=new TreeNode(postorder[pend]);
if(pStart==pend)
return root;
int mid=iStart;
while(mid<=iend && inorder[mid]!=root.val)
mid++;
int leftCount=mid-iStart;
root.left=buildTree(inorder,postorder,iStart,mid-1,pStart,pStart+leftCount-1);
root.right=buildTree(inorder,postorder,mid+1,iend,pStart+leftCount,pend-1);
return root;
}
}
博学 审问 慎思 明辨 笃行