力扣第105题-从前序与中序遍历序列构造二叉树

257 阅读3分钟

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

前言

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

给定一棵树的前序遍历 preorder 与中序遍历  inorder。请构造二叉树并返回其根节点。

示例 1:

Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]

image.png

一、思路

题目意思很明确,就是根据前序遍历和中序遍历,还原出二叉树

题目中有一个需要注意的提示:preorder 和 inorder 均无重复元素

我们其实可以想一个问题,为什么靠前序遍历不能还原一个二叉树呢?

举个例子,假设前序遍历的结果为 [1, 2, 3]。你能还原二叉树吗?很明显是不能的,因为会有如下的两种情况。

第一种情况:

image.png

第二种情况:

image.png

但是如果告诉你前序遍历的结果为 [1, 2, 3],中序遍历的结果为 [2, 1, 3]。那么很容易就知道,这样还原的结果为第一种情况。

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

  • 前序遍历:根左右
  • 中序遍历:左根右

又因为二叉树中没有重复的节点值,所以 前序遍历中的第一个节点为根节点。所以在中序遍历中在根节点前面的值为左子树,右边的值为右子树。这样就能还原出二叉树了。

图解算法

此处以示例一中的 preorder = [3,9,20,15,7], inorder = [9,3,15,20,7] 作为例子。

  1. 根据前序遍历的特性,很容易就知道第一个节点 3 是根节点 image.png

  2. 将中序遍历中的结果根据根节点分割,分为左子树和右子树

image.png

  1. 因为左子树只有一个节点 9,直接作为叶子节点即可。我们知道左子树只有一个节点,所以右子树的根节点为前序遍历的第三个节点

image.png

  1. 右子树在分割为左右子树即可,如下图:

image.png

  1. 最终的结果如下所示:

image.png

二、实现

实现代码

实现代码与思路基本保持一致,唯一需要注意的是:我们先使用了 HashMap 来存储中序遍历中个节点的位置,防止重复的在中序遍历中寻找目标位置

    private Map<Integer, Integer> inMap;

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

    /**
     *
     * @param left  中序遍历中左子树起始位置
     * @param right 中序遍历中右子树起始位置
     * @param rootIndex 前序遍历中根节点值
     * @return
     */
    public TreeNode dfs(int[] preorder, int left, int right, int rootIndex) {
        if (left > right) {
            return null;
        }
        int inorder_root = inMap.get(preorder[rootIndex]);
        TreeNode root = new TreeNode(preorder[rootIndex]);
        root.left = dfs(preorder, left, inorder_root-1, rootIndex+1);
        root.right = dfs(preorder, inorder_root+1, right, rootIndex+inorder_root-left+1);
        return root;
    }

测试代码

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

结果

image.png

三、总结

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

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