从零学算法

106.给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
示例 1:
输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
输出:[3,9,20,null,null,15,7]
示例 2:
输入:inorder = [-1], postorder = [-1]
输出:[-1]

  • 直接上他人解法:首先我们需要知道后序遍历是什么,就是以左右中的顺序遍历一棵树,那么我们就能知道,后序遍历的结果数组中,最后一个数就是根节点。其次中序遍历是以左中右的顺序遍历一棵树,那么现在我们知道了根节点的值,以这个值为分界线,左边肯定是这棵树的左边部分,右边就是这棵树的右边部分。以为一颗 [1,2,3] 的数为例好了,中序遍历是 [2,1,3],后序遍历是 [2,3,1],后序遍历的结果的最后一个数 1 是根节点,把 1 放在中序遍历的结果来看,左边的 2 确实就是左节点,右边的 3 为右节点。这只是我们要递归的一个最小单元,我们还需要想一下递归的入参,想想如果是一颗三层的树,当你从中序数组得到了左半部分的树以后,你需要递归继续分这部分,也就是说以当前左半部分为一个小的中序数组,你还需要在后序数组中得到这一部分为一个小的后序数组,右半部分同理。也就是说在一次递归中我们需要知道当前处理的中序数组是哪一段,当前处理的后续数组是哪一段,定义四个变量 is:中序数组起点,ie:中序数组终点,ps:后序数组起点,pe:后序数组终点。接下来就是最核心的问题:怎么得到这四个点。首先最开始不用说,我们要处理的就是完整的两个结果数组,也就是 {is: 0, ie: inorder.length-1, ps: 0, pe: postorder.length-1}。按照上面说的思路先得到当前递归时的根节点也就是 postorder[pe],然后得到根节点在中序数组中的坐标 ri 来得到树的左右两部分。那么我们先拿中序数组中的左半部分,is 很明显还是 is,ie 也很明显,ri 的左边都是树左半部分,所以为 ri - 1,汇总一下:{is:is, ie: ri-1};再拿后序数组中的左半部分,首先 ps 也不变还是为 ps,pe 的话我们就先根据中序数组得到这半部分的长度为 ri-1-is ,起点加长度就得到了 pe 为 ps+ri-1-is,这样我们就得到了左半部分的中序数组和后序数组。右半部分同理。
  •   // 这里用 hashMap 存了中序数组每个值对应的坐标
      HashMap<Integer,Integer> memo = new HashMap<>();
      int[] post;
      public TreeNode buildTree(int[] inorder, int[] postorder) {
          post = postorder;
          for(int i = 0;i < inorder.length; i++) memo.put(inorder[i], i);
          return solve(0,inorder.length-1,0,post.length-1);
      }
      public TreeNode solve(int is, int ie, int ps, int pe){
          if(is > ie || ps > pe){
              return null;
          }
          // 当前根节点的值
          int rv = post[pe];
          // 当前根节点坐标
          int ri = memo.get(rv);
          TreeNode root = new TreeNode(rv);
          root.left=solve(is,ri-1,ps,ps+ri-is-1);
          root.right=solve(ri+1,ie,ps+ri-is,pe-1);
          return root;
      }
    

你可能感兴趣的:(算法学习,算法,java,开发语言)