zoukankan      html  css  js  c++  java
  • 【LeetCode】106.从中序与后序遍历序列构造二叉树(含有递归参数少的解法)

    题目地址:https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/

    题目

    1. 从中序与后序遍历序列构造二叉树
      根据一棵树的中序遍历与后序遍历构造二叉树。
      注意:
      你可以假设树中没有重复的元素。
      例如,给出
      中序遍历 inorder = [9,3,15,20,7]
      后序遍历 postorder = [9,15,7,20,3]
      返回如下的二叉树:
     	3
       / 
      9  20
        /  
       15   7
    

    思路分析:

    首先,来一棵树

    在这里插入图片描述

    然后再看树的遍历结果

    在这里插入图片描述

    根据中序和后序遍历结果还原二叉树

    中序遍历和后续遍历的特性
    首先来看题目给出的两个已知条件中序遍历序列和后序遍历序列 根据这两种遍历的特性我们可以得出两个结论

    1. 在后序遍历序列中,最后一个元素为树的根节点
    2. 在中序遍历序列中,根节点的左边为左子树,根节点的右边为右子树

    如下图所示:
    在这里插入图片描述

    树的还原过程变量定义

    需要定义几个变量帮助我们进行树的还原
    1.HashMap memo 需要一个哈希表来保存中序遍历序列中,元素和索引的位置关系.因为从后序序列中拿到根节点后,要在中序序列中查找对应的位置,从而将数组分为左子树和右子树
    2.int ri 根节点在中序遍历数组中的索引位置
    3.中序遍历数组的两个位置标记 [is, ie],is是起始位置,ie是结束位置
    4.后序遍历数组的两个位置标记 [ps, pe] ps是起始位置,pe是结束位置

    位置关系的计算

    在找到根节点位置以后,我们要确定下一轮中,左子树和右子树在中序数组和后续数组中的左右边界的位置。

    1. 左子树-中序数组 is = is, ie = ri - 1
    2. 左子树-后序数组 ps = ps, pe = ps + ri - is -1 (pe计算过程解释,后续数组的起始位置加上左子树长度-1 就是后后序数组结束位置了,左子树的长度 = 根节点索引-左子树)
    3. 右子树-中序数组 is = ri + 1, ie = ie
    4. 右子树-后序数组 ps = ps + ri - is, pe - 1

    听不明白没关系,看图就对了,计算图示如下
    在这里插入图片描述

    树的还原过程

    在这里插入图片描述

    代码如下所示:

    class Solution {
    
        HashMap<Integer,Integer> memo = new HashMap<>();
        int[] post;
    
        public TreeNode buildTree(int[] inorder, int[] postorder) {
            for(int i = 0;i < inorder.length; i++) memo.put(inorder[i], i);
            post = postorder;
            TreeNode root = buildTree(0, inorder.length - 1, 0, post.length - 1);
            return root;
        }
    
        public TreeNode buildTree(int is, int ie, int ps, int pe) {
            if(ie < is || pe < ps) return null;
    
            int root = post[pe];
            int ri = memo.get(root);
    
            TreeNode node = new TreeNode(root);
            node.left = buildTree(is, ri - 1, ps, ps + ri - is - 1);
            node.right = buildTree(ri + 1, ie, ps + ri - is, pe - 1);
            return node;
        }
    }
    

    难点分析:

    这道题主要的难点就是在于数组边界的划分。需要我们自己把图画出来,一个个的把数组的范围确立并且用对应的变量表达。
    还使用的哈希表来存放中序遍历,便于在之后找到根节点在中序遍历数组中的下标。

    另外一种方法

    这种方法不用确定后序遍历数组的边界。所以在递归时传递的参数比较好,但理解起需要费一些脑力。

    后序是左–右--根的特点,所以后序遍历从后向前是根–右--左,故在递归时根本没有必要将后序遍历的数组界限传入,每次有节点加入就自减一就行,只要满足了先拿到根节点然后遍历右子树,再遍历左子树这个原则就Okay。

       Map<Integer, Integer> map = new HashMap<>();//存放中序的映射
        int pindex = 0;//后序的索引
        public TreeNode buildTree(int[] inorder, int[] postorder) {
            pindex = postorder.length - 1;//因为二叉树的第一个节点对应后序的最后一个,从最后一个开始
            for (int i = 0; i < inorder.length; i++) {
                map.put(inorder[i], i);
            }
            return build(postorder, 0, inorder.length - 1);
        }
    
        /**
         *
         * @param postorder 后序链表
         * @param inl 中序的左边界
         * @param inr 中序的右边界
         * @return 二叉树节点
         */
        public TreeNode build(int[] postorder, int inl, int inr) {
            if (inl > inr) return null;
            TreeNode node = new TreeNode(postorder[pindex--]);//从最后一个开始初始化为TreeNode。
            //注意上面的postorder[pindex--],此处相当于postorder[pindex],pindex--;
            
            int index = map.get(node.val);//得到在中序的索引
            node.right = build(postorder, index + 1, inr);//先遍历右子树
            node.left = build(postorder, inl, index - 1);//再遍历左子树
            return node;
        }
    
    
  • 相关阅读:
    HDU1565_方格取数(1)
    HDU3046_Pleasant sheep and big big wolf
    HDU4183_Pahom on Water
    「zoj2314」Reactor Cooling (无源汇上下界可行流)
    [ACM-ICPC 2018 沈阳网络赛] G. Spare Tire (思维+容斥)
    [ACM-ICPC 2018 沈阳网络赛] D. Made In Heaven (k短路模板)
    lct,半平面交,线性基,k短路
    P3950 部落冲突 (LCT暴力)
    P4219 [BJOI2014]大融合 ( LCT维护虚实子树size )
    P3203 [HNOI2010]弹飞绵羊(LCT维护链的size + 思维)
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13308078.html
Copyright © 2011-2022 走看看