题目描述:
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
让我们先回顾一下二叉树遍历的知识点:
前序遍历:根→左→右,根在前,子树在根后且左子树比右子树靠前
中序遍历:左→根→右,根在中,左子树在跟左边,右子树在根右边
后序遍历:左→右→根,根在后,子树在跟前且左子树比右子树靠前
已知前序遍历和中序遍历,如何利用递归来得到二叉树呢:
1 确定根,确定左子树,确定右子树。
2 在左子树中递归。
3 在右子树中递归。
4 打印当前根。
下面给出具体事例进行说明分析:
已知前序序列{ A B H F D E C K G},中序序列{ H B D F A E K C G}
1.根据前序序列的特点,可知根节点为A
2.根据中序遍历,可以得知根节点A左侧的HBDF必定为根节点A的左子树,根节点A右侧的EKCG必定为根节点A的右子树
3.继续根据前序和中序的规则,拆分左子树(HBDF),确认B 为左子树的根节点,H为左节点,DF为右节点
4.再继续根据前序和中序的规则,分析DF,可知F为根节点,D为左节点,没有右节点
5.同样的道理,根节点的右子树节点EKCG中的根节点也可以通过前序遍历求得。在前序遍历中,一定是先把根节点和根节点的所有左子树节点遍历完之后才会遍历右子树,并且遍历的左子树的第一个节点就是左子树的根节点。同理,遍历的右子树的第一个节点就是右子树的根节点,即E。进一步分析还可知没有左节点,只有右节点(KCG)
6.继续拆分右子树,可确认C为根节点,左节点K,右节点 G
总结:观察发现,上面的过程是递归的。先找到当前树的根节点,然后划分为左子树,右子树,然后进入左子树重复上面的过程,然后进入右子树重复上面的过程。最后就可以还原出一棵二叉树。
因此该题目通过程序实现,代码如下:
/* function TreeNode(x) {
this.val = x;
this.left = null;
this.right = null;
} */
function reConstructBinaryTree(pre, vin){
if(pre.length ==0 || vin.length ==0){
return null;
}
var binaryTree = new TreeNode(pre[0]);
var pre_left = [],
pre_right = [],
vin_left = [],
vin_right = [];
var index = vin.indexOf(pre[0]);
pre_left = pre.slice(1, index + 1);
pre_right = pre.slice(index + 1);
vin_left = vin.slice(0, index);
vin_right = vin.slice(index + 1);
binaryTree.left = reConstructBinaryTree(pre_left, vin_left);
binaryTree.right = reConstructBinaryTree(pre_right, vin_right);
return binaryTree;
}
文章同步: levinhax's Github Blog