递归(三)从前序与中序遍历序列构造二叉树

对应 LeetCode 105 从前序与中序遍历序列构造二叉树

问题描述

给定两个整数数组 \(pre\)\(in\),其中 \(pre\) 是二叉树的先序遍历结果,而 \(in\) 是改二叉树的中序遍历结果,请通过 \(pre\)\(in\) 来重新构建该二叉树并返回其对应的根节点

提示:

  • 该二叉树中不存在重复元素

  • \(0 \leq\) 节点数 \(\leq5000\)

解决思路

  • 递归

    同样的,在处理树的问题时,优先考虑使用递归的方式进行处理

    在这里,由于给定了先序遍历和中序遍历,在每次递归时都能够确定每个根节点的位置,因此该算法在理论上是可行的

    只需注意每次处理的位置即可,递归的终止条件为待处理的数据列表的长度为 \(0\)

  • 递归 + HashMap

    可以通过引入 HashMap 来提高搜索根节点的位置,但是这种方式只能处理不包含重复元素的二叉树

实现

  • 递归

    class Solution {
        int[] pre, in;
    
        public TreeNode buildTree(int[] _pre, int[] _in) {
            pre = _pre;in = _in;
            int n = pre.length;
    
            return recur(0, n - 1, 0, n - 1);
        }
    
        TreeNode recur(int preLo, int preHi, int inLo, int inHi) {
            if (preLo > preHi || inLo > inHi) 
                return null;
    
            int e = pre[preLo], idx = -1;
            // 这里通过查找和当前先序遍历访问的节点记性比较,相同则为根节点
            for (int i = inLo; i <= inHi; ++i) {
                if (in[i] == e) {
                    idx = i;
                    break;
                }
            }
    
            if (idx < 0) throw new IllegalArgumentException();
    
            TreeNode root = new TreeNode();
            root.val = e;
            // 注意这里左右区间的范围
            root.left = recur(preLo + 1, preHi, inLo, idx - 1);
            root.right = recur(preLo + idx - inLo + 1, preHi, idx + 1, inHi);
    
            return root;
        }
    }
    

    复杂度分析:

    • 时间复杂度:递归处理需要 \(O(n)\) 的时间复杂度,根节点的查找操作需要 \(O(n)\) 的时间复杂度,整体时间复杂度为 \(O(n^2)\)

    • 空间复杂度:忽略由于递归带来的开销,总体空间复杂度为 \(O(1)\)

  • 递归 + HashMap

    class Solution {
        int[] pre, in;
        final Map<Integer, Integer> map = new HashMap<>();
    
        public TreeNode buildTree(int[] _pre, int[] _in) {
            pre = _pre;in = _in;
            int n = pre.length;
            for (int i = 0; i < n; ++i) map.put(in[i], i);
    
            return recur(0, n - 1, 0, n - 1);
        }
    
        TreeNode recur(int preLo, int preHi, int inLo, int inHi) {
            if (preLo > preHi || inLo > inHi) 
                return null;
    
            int e = pre[preLo], idx = map.get(e);
    
            TreeNode root = new TreeNode();
            root.val = e;
            root.left = recur(preLo + 1, preHi, inLo, idx - 1);
            root.right = recur(preLo + idx - inLo + 1, preHi, idx + 1, inHi);
    
            return root;
        }
    }
    

    复杂度分析:

    • 时间复杂度:递归处理需要 \(O(n)\) 的时间复杂度,HashMap 进行查找操作需要 \(O(1)\) 的时间复杂度,总体时间复杂度为 \(O(n)\)

    • 空间复杂度:存储 HashMap 需要额外的空间,空间复杂度为 \(O(1)\)

posted @ 2022-03-02 14:55  FatalFlower  阅读(46)  评论(0编辑  收藏  举报