LeetCode 105. 从前序与中序遍历序列构造二叉树(递归分治法)

一、题目描述

给定两个整数数组preorder(前序遍历)和inorder(中序遍历),构造二叉树并返回根节点。

前序:根 → 左 → 右;中序:左 → 根 → 右;题目保证节点值互不相同。

二、核心思路

  1. 前序数组第一个元素一定是当前子树的根节点。
  2. 在中序数组找到根节点下标:根左侧全部为左子树节点,右侧全部为右子树节点。
  3. 计算左子树节点数量leftSize = rootIdx - inL,用这个数量切割前序数组,分出左、右子树对应的前序区间。
  4. 递归分别构建左子树、右子树;区间无效(preL > preR)时递归终止,返回null。
  5. 哈希表优化:提前存储中序数组「值→下标」,查找根位置(O(1))。

三、完整 Java 代码

ini 复制代码
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    Map<Integer, Integer> map;
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        map = new HashMap<>();
        for(int i = 0; i < inorder.length; i++){
            map.put(inorder[i], i);
        }
        return build(preorder, 0, preorder.length-1, 0, inorder.length-1);
    }

    private TreeNode build(int[] pre, int preL, int preR, int inL, int inR){
        if(preL > preR) return null;
        int rootVal = pre[preL];
        TreeNode root = new TreeNode(rootVal);
        int rootIdx = map.get(rootVal);
        int leftSize = rootIdx - inL;

        root.left = build(pre, preL+1, preL+leftSize, inL, rootIdx-1);
        root.right = build(pre, preL+leftSize+1, preR, rootIdx+1, inR);
        return root;
    }
}

四、实例推演表格

样例:preorder=[3,9,20,15,7],inorder=[9,3,15,20,7]

递归调用 preL,preR inL,inR rootVal rootIdx leftSize 动作
第一层 0,4 0,4 3 1 1 左子树 pre 1,1,右子树 pre 2,4
根 3 的左子树 1,1 0,0 9 0 0 左右子树均为 null
根 3 的右子树 2,4 2,4 20 3 2 左子树 pre 3,3,右子树 pre 4,4
根 20 的左子树 3,3 2,2 15 2 0 左右子树均为 null
根 20 的右子树 4,4 4,4 7 4 0 左右子树均为 null

五、复杂度分析

  • 时间复杂度:(O(n)),n 为节点数。哈希表预处理(O(n)),每个节点递归构建一次,哈希查找(O(1))。
  • 空间复杂度:(O(n)),哈希表存储全部节点;递归栈最坏(O(n))(单链树),平衡二叉树(O(logn))。

六、易错点总结

  1. inL不是固定等于 0,每次递归随当前子树区间动态改变;leftSize = rootIdx - inL,表示当前子树在中序区间内根左边节点数量。
  2. 区间边界:左子树前序[preL+1, preL+leftSize];右子树起点必须preL+leftSize+1,不要漏 + 1。
  3. 递归终止条件:preL > preR,区间相等时还有一个节点,需要创建节点,不能直接返回 null。
  4. 哈希表可用前提:题目节点值不重复。

七、个人感悟

这道题核心是前序找根,中序划分左右。不需要切割数组,只用下标标记区间,节省数组拷贝开销;哈希表是重要优化,不使用哈希表时间复杂度退化为(O(n^2))。递归分治思想,把大问题拆成构造左子树、构造右子树两个子问题。

相关推荐
longlongzihan1 小时前
LeetCode 24.两两交换链表中的节点:虚拟头结点与指针
算法·leetcode·链表
longlongzihan1 小时前
从LeetCode 19. 删除链表的倒数第 N 个结点深入理解“哨兵节点”
c++·算法·leetcode·链表
java_nnnn2 小时前
LeetCode刷题滑动窗口(长度最小的子数组)
算法·leetcode·职场和发展
yi0113 小时前
DAY27: LeetCode 110. 平衡二叉树 | 在递归中判断是否平衡
人工智能·笔记·python·算法·leetcode·二叉树·递归
Nil20813 小时前
leetcode 763划分字母区间
算法·leetcode·职场和发展
不会就选b13 小时前
算法日常・每日刷题--<动态规划>20
算法·leetcode·动态规划
不会就选b14 小时前
算法日常・每日刷题--<动态规划>19
算法·leetcode·职场和发展
垆边人似月.16 小时前
华为机试题 :和为 K 的子数组个数
算法·leetcode·华为
夏幻灵17 小时前
每日一题:LeetCode 165:比较版本号
算法·leetcode·职场和发展