LeetCode_Construct Binary Tree from Inorder and Postorder Traversal
Posted rotk2015
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode_Construct Binary Tree from Inorder and Postorder Traversal相关的知识,希望对你有一定的参考价值。
给定二叉树中序、后序遍历结果,构建二叉树。
- 后序的最后一个结点必为根节点。
- 对于后序的最后一个结点而言,中序遍历结果中,位于它左边的是它的左子树,位于它右边的是它的右子树。
- 由 2 可得基本递归思路一:不断利用后序最后一个节点将中序结果分割,自底向上递归建立左右子树即可。此时,由于要在中序结果中寻找后序最后结点,故要么每次都循环遍历(时间代价),要么提前建立一个哈希表(空间代价)作为参数。
- 本文的重点是第二种递归思路,既不循环也不需要哈希表。
- 代码如下(转自参考资料):
int pInorder; // index of inorder array int pPostorder; // index of postorder array private TreeNode buildTree(int[] inorder, int[] postorder, TreeNode end) if (pPostorder < 0) return null; // create root node TreeNode n = new TreeNode(postorder[pPostorder--]); // if right node exist, create right subtree if (inorder[pInorder] != n.val) n.right = buildTree(inorder, postorder, n); pInorder--; // if left node exist, create left subtree if ((end == null) || (inorder[pInorder] != end.val)) n.left = buildTree(inorder, postorder, end); return n; public TreeNode buildTree(int[] inorder, int[] postorder) pInorder = inorder.length - 1; pPostorder = postorder.length - 1; return buildTree(inorder, postorder, null);
- 代码整体亦使用递归思路,同时还使用了两个函数外指针变量分别遍历两个结果。
- 右子树的判断:先以后序遍历的末尾值建立根结点 n,此时判定对应位置的中序结果(inorder[pInorder])是否与后序(n.val)的一致,若不一致,说明该根结点有右子树,导致后序遍历的末尾值在中序遍历不在末尾,则进入递归函数进行右子树结点的建立,循环往复直至当前结点(n.val)处于中序末尾,也就是二叉树最右结点。此外,需要注意的是,后序指针(pPostorder )在建立完当前结点后立即前移。
- 在递归进入并建立完最深一层的最右结点后,中序指针前移。此时需要进行左子树的判断。
- 左子树的判断:左子树相比于右子树要较难一些。为便于说明,称以当前结点(n)为右子结点的根结点为“父结点”、当前结点的左子结点(n.left)为“左结点”。第8点提到了中序指针前移,若当前结点没有左结点(或左子树)时,前移后的中序指针应恰好指向父结点;而若有左结点(或左子树),则中序结果中,左结点(或左子树)会插在父结点与当前结点之间。也就是说,父结点是左结点(或左子树)的边界(TreeNode end is the boundary of left subtree.)。那么,我们该怎么做呢?判定前移后的中序指针指向的是否为父结点。问题是,如何得知父结点具体是多少呢?
- 这就得介绍一下我们的递归函数的第三个形参:TreeNode end。从右子树部分的递归调用语句中可以看出,我们通过它将当前结点作为根结点传递给下一层递归,也就是说,当前层的形参TreeNode end里存放的就是我们在第9条中需要的边界信息——父结点。而在左子树部分,由于可能会进行多次递归,故要将本层接收到的形参(TreeNode end,并不是TreeNode n)作为实参继续传递给下一层(在递归传递过程中,end并不是一成不变的,当递归到某一步遇到有右子树的情况时,需要展开新的递归,此时,那一层创建的当前结点n是新展开的递归分支的end,而这个递归分支也可能展开另一个分支…但无论情况有多么复杂,当递归一层层退回的时候,通过压栈入栈又可恢复原本的正确的end)。
- 然而,引入TreeNode end作为形参会带来一个新问题。对于一个二叉树而言,最顶结点没有父结点。那么,在一开始启动这个递归函数的时候,又该传递给它什么实参呢?答案是null,我们将最顶结点的父结点,人为定义为null,换个角度讲,最顶结点(或者说它代表的整个二叉树)被看作是null的右子结点(或右子树)。那么对应的,在判断是否有左子树的时候,就得增加一个“或”条件判断end是否为null。
- 另,题中给定了一个限制条件是二叉树结点无重复值,读者可思考在有重复值的情况下, 哪些步骤会失效。在这种复杂情况下,又该以何作为判定依据。
参考:
以上是关于LeetCode_Construct Binary Tree from Inorder and Postorder Traversal的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode_Construct Binary Tree from Inorder and Postorder Traversal
Binary Tree和Binary Search Tree
[Leetcode] Binary tree -- 617. Merge Two Binary Trees
无法引用 org.apache.commons.codec.binary.Base64;
[Leetcode] Binary tree-- 606. Construct String from Binary Tree