【LeetCode】105. 根据一棵树的前序遍历与中序遍历构造二叉树。(同剑指 Offer 07)

根据给定的前序和中序遍历,本文介绍了两种方法(递归和迭代)来构造二叉树。递归法通过建立根节点并划分左右子树进行构造,而迭代法则利用栈来找到右孩子的父节点。两种方法的时间复杂度均为O(n),空间复杂度取决于树的形状。
摘要由CSDN通过智能技术生成

一、题目

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

例如,给出

前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]

返回如下的二叉树:

    3
   / \
  9  20
    /  \
   15   7

二、解决

1、递归

思路:

前序遍历:【根节点】【左子树】【右子树】
中序遍历:【左子树】【根节点】【右子树】

推论:
1、前序遍历首元素为树的根节点node的值;
2、中序遍历中,搜索node索引,然后以此为界,可将中序遍历划分为【左子树】【根节点】【右子树】,记录左、右子树的节点数量leftCnt & rightCnt
3、根据leftCnt & rightCnt可以将 前序遍历 划分为【根节点】【左子树】【右子树】。
1
过程:

  1. 递推参数:前序遍历索引root、子树在中序遍历左边界left、子树在中序遍历的有边界right;
  2. 终止条件:left > right,代表越过根节点,此时返回null;
  3. 递归工作:
    3.1. 建立根节点node:节点值为preorder[root];
    3.2. 划分左右子树:查找根节点在中序遍历inorder中的索引 i ;
    为提升效率,本文使用哈希表dic存储中序遍历的值与索引的映射,查找操作的时间复杂度为O(1);
    3.3 构建左右子树:开启左右子树递归
根节点索引 中序遍历左边界 中序遍历右边界
左子树 root+1 left i-1
右子树 i-left+root+1 i+1 right

代码-版本1:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */

class Solution {
   
    int[] preorder;
    HashMap<Integer, Integer> dic = new HashMap<>();
    public TreeNode buildTree(int[] preorder, int[] inorder) {
   
        this.preorder = preorder;
        for(int i = 0; i < inorder.length; i++)
            dic.put(inorder[i], i);
        // return recur(0, 0, inorder.length - 1); 
       // 传入参数:前序,中序,前序序列根节点,中序序列左边界,中序序列右边界
        return build(preorder, inorder, 0, 0, inorder.length-1);
    }
    private TreeNode build (int[] preorder, int[] inorder, int preRoot, int inLeft, int inRight) {
   
        if(inLeft > inRight)  return null;
        TreeNode root = new TreeNode(preorder[preRoot]);
        // 根节点在中序序列中的位置,用于划分左右子树的边界
        int inRoot = dic.get(preorder[preRoot]);
        // 左子树在前序中的根节点位于:preRoot+1,左子树在中序中的边界:[inLeft, inRight-1]
        root.left = build(preorder, inorder, preRoot+1, inLeft, inRoot-1);
        // 右子树在前序中的根节点位于:根节点+左子树长度+1 = preRoot+inRoot-inLeft+1
        // 右子树在中序中的边界:[inRoot+1,inRight]
        root.right = build(preorder, inorder, preRoot+inRoot-inLeft+1, inRoot+1, inRight);
        return root;
    }
}

代码-版本2: (对版本1 代码进一步精简后)

class Solution {
   
    int[] preorder;
    HashMap<Integer, Integer> dic = new HashMap<>();
    public
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值