力扣第106题-从中序与后序遍历序列构造二叉树前言一、思

「这是我参与11月更文挑战的第25天,活动详情查看:2021最后一次更文挑战

前言

力扣第106题 从中序与后序遍历序列构造二叉树 如下所示:

根据一棵树的中序遍历与后序遍历构造二叉树。

注意:
你可以假设树中没有重复的元素。

例如,给出

中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]
复制代码

返回如下的二叉树:

    3
   / \
  9  20
    /  \
   15   7
复制代码

一、思路

题目意思很明确:利用中序和后序遍历还原二叉树。这一题昨天写的那一题非常的相似,思路也是差不多的,有兴趣的可以看一下# 力扣第105题-从前序与中序遍历序列构造二叉树

我们知道中序遍历和后序遍历有如下的特点:

  • 中序遍历:先 左子树节点,再 根节点,最后是 右子树节点
  • 后序遍历:先 左子树节点,再 右子树节点,最后是 根节点

如果问你二叉树的根节点是什么?你知道吗?

很显然二叉树的根节点就是 后序遍历 的最后一个元素了。那子树的根节点又是什么呢?这与当前子树的起始位置和节点数量有关了,不妨继续向下看以下图文分析。

图解算法

此处以实例中的 inorder = [9,3,15,20,7],postorder = [9,15,7,20,3] 作为例子,用表格画一下,就如下所示:

image.png

  1. 确定第一个根节点 root1,很显然是后序遍历的最后一个节点

image.png

  1. 再在中序遍历中找到这个根节点的位置,确定出左子树 left1 和右子树 right1。如下图所示:

image.png

  1. 我们再确认左子树 left1 的根节点

    因为根节点 root1 在中序遍历中的位置是 2,说明右子树有 3 个节点。所以 left1 的根节点是 root1 向前移动 4 格的位置(要除去自身)

image.png

  1. 再确认右子树 right1 的根节点,只需要将 root1 前移动 1 格即可。(因为后续遍历是左右根,根节点前面就是右子树的最后一个节点,即右子树的根节点)

image.png

  1. 我们找到了所有的根节点,那么还原这个二叉树也就不是什么难事了。最终的结果如下图所示:

image.png

二、实现

实现代码

实现代码与思路中保持一致,为了避免多次在 中序遍历 中找目标值,所以先用 Map 存储了中序遍历所有的节点值和位置。

    private Map<Integer, Integer> inMap;

    public TreeNode buildTree(int[] inorder, int[] postorder) {
        int n = inorder.length;
        int m = postorder.length;
        // 构造哈希映射,记住中序遍历中每个节点的位置
        inMap = new HashMap<>();
        for (int i=0; i<n; i++) {
            inMap.put(inorder[i], i);
        }
        return dfs(postorder, 0, n-1, m-1);
    }

    /**
     * @param postorder 后序遍历
     * @param inLeft 中序遍历左子树起始位
     * @param inRight 中序遍历右子树起始位
     * @param postRoot 后续遍历中根节点的位置
     * @return
     */
    public TreeNode dfs(int[] postorder, int inLeft, int inRight, int postRoot) {
        if (inLeft > inRight)
            return null;
        // 后序遍历中从后往前都是根节点
        TreeNode root = new TreeNode(postorder[postRoot]);
        int inorder_root = inMap.get(postorder[postRoot]);
        root.left = dfs(postorder, inLeft, inorder_root-1, postRoot-(inRight-inorder_root)-1);
        root.right = dfs(postorder, inorder_root+1, inRight, postRoot-1);
        return root;
    }
复制代码

测试代码

    public static void main(String[] args) {
        int[] inorder = {9,3,15,20,7};
        int[] postorder = {9,15,7,20,3};
        TreeNode treeNode = new Number106().buildTree(inorder, postorder);
        System.out.println("test");
    }
复制代码

结果

image.png

三、总结

感谢看到最后,非常荣幸能够帮助到你~♥

如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~