LeetCode_Construct Binary Tree from Inorder and Postorder Traversal

2023-10-16 07:08

本文主要是介绍LeetCode_Construct Binary Tree from Inorder and Postorder Traversal,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

给定二叉树中序、后序遍历结果,构建二叉树。

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

参考:

  1. 力扣对应题目讨论区的某答案下第一个评论。

这篇关于LeetCode_Construct Binary Tree from Inorder and Postorder Traversal的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/219868

相关文章

哈希leetcode-1

目录 1前言 2.例题  2.1两数之和 2.2判断是否互为字符重排 2.3存在重复元素1 2.4存在重复元素2 2.5字母异位词分组 1前言 哈希表主要是适合于快速查找某个元素(O(1)) 当我们要频繁的查找某个元素,第一哈希表O(1),第二,二分O(log n) 一般可以分为语言自带的容器哈希和用数组模拟的简易哈希。 最简单的比如数组模拟字符存储,只要开26个c

uva 575 Skew Binary(位运算)

求第一个以(2^(k+1)-1)为进制的数。 数据不大,可以直接搞。 代码: #include <stdio.h>#include <string.h>const int maxn = 100 + 5;int main(){char num[maxn];while (scanf("%s", num) == 1){if (num[0] == '0')break;int len =

leetcode-24Swap Nodes in Pairs

带头结点。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/public class Solution {public ListNode swapPairs(L

leetcode-23Merge k Sorted Lists

带头结点。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/public class Solution {public ListNode mergeKLists

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

【JavaScript】LeetCode:16-20

文章目录 16 无重复字符的最长字串17 找到字符串中所有字母异位词18 和为K的子数组19 滑动窗口最大值20 最小覆盖字串 16 无重复字符的最长字串 滑动窗口 + 哈希表这里用哈希集合Set()实现。左指针i,右指针j,从头遍历数组,若j指针指向的元素不在set中,则加入该元素,否则更新结果res,删除集合中i指针指向的元素,进入下一轮循环。 /*** @param

树(Tree)——《啊哈!算法》

树 什么是树?树是一种特殊的图,不包含回路的连通无向树。 正因为树有着“不包含回路”这个特点,所以树就被赋予了很多特性。 一棵树中的任意两个结点有且仅有唯一的一条路径连通。一棵树如果有n个结点,那么它一定恰好有n-1条边。在一棵树中加一条边将会构成一个回路。 一棵树有且只有一个根结点。 没有父结点的结点称为根结点(祖先)。没有子结点的结点称为叶结点。如果一个结点既不是根结点也不是叶

LeetCode:64. 最大正方形 动态规划 时间复杂度O(nm)

64. 最大正方形 题目链接 题目描述 给定一个由 0 和 1 组成的二维矩阵,找出只包含 1 的最大正方形,并返回其面积。 示例1: 输入: 1 0 1 0 01 0 1 1 11 1 1 1 11 0 0 1 0输出: 4 示例2: 输入: 0 1 1 0 01 1 1 1 11 1 1 1 11 1 1 1 1输出: 9 解题思路 这道题的思路是使用动态规划