JAVA练习29-重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。

假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

示例 1:


输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]

示例 2:
输入: preorder = [-1], inorder = [-1]
输出: [-1]

限制:

  • 0 <= 节点个数 <= 5000

分析:

先序遍历的形式是:根节点 - 左子树先序遍历结果 - 右子树先序遍历结果

中序遍历的形式是:左子树中序遍历结果 - 根节点 - 右子树中序遍历结果

方法1:分治算法

由先序遍历的形式可以知道,先序数组的第一个一定为根节点,那么我们可以根据这个根节点找到中序数组对应根节点的索引,根据这个索引,我们可以知道左右子树的长度以及在中序数组对应的范围,根据左右子树的长度,我们又可以知道先序数组对应左右子树的范围,从而知道左右子树的根节点,然后我们根据这根节点继续执行相同操作就可以得到重建二叉树了。

时间复杂度:O(n^2)
空间复杂度:O(n) 

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

    //记录数组长度
    int len;
    //先序和中序数组
    int[] preorder, inorder;

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        len = preorder.length;
        //空数组直接返回空
        if(len == 0){
            return null;
        }
        this.preorder = preorder;
        this.inorder = inorder;
        //重建二叉树
        TreeNode root = buildTree(0, len, 0);
        return root;
    }

    public TreeNode buildTree(int i, int j, int k){
        //创建当前位置对应数组节点
        TreeNode node = new TreeNode(preorder[k]);
        //记录根节点位置
        int root = 0;
        //遍历寻找根节点位置
        for(int a = i; a < j; a++){
            if(inorder[a] == preorder[k]){
                root = a;
                break;
            }
        }
        //先序遍历根节点一般为下一个左根节点,所以执行加一操作,后面在判断是不是为左节点
        k++;
        //进行下一层根节点操作
        //判断是否有左根节点
        if(root > i){
            node.left = buildTree(i, root, k);
        }
        //判断是否有右节点
        if(1 + root < j && k+root-i < len){
            node.right = buildTree(root+1, j, k+root-i);
        }
        return node;
    }
}

方法2: 分治算法+HashMap

如果按照方法 1 ,每一次递归都要在中序遍历数组中找一次根节点索引,浪费时间,因为题目的条件提到遍历的结果不包含重复数字,那么可以利用 HashMap 来存储中序遍历数组的索引,数字作为键值,那么每一次递归直接根据数字就可以找到对应根节点索引。

时间复杂度:O(n)
空间复杂度:O(n) 

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

    //记录数组长度
    int len;
    //先序
    int[] preorder;
    //利用HashMap记录中序
    HashMap<Integer, Integer> map;

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        len = preorder.length;
        //空数组直接返回空
        if(len == 0){
            return null;
        }
        this.preorder = preorder;
        map = new HashMap<>();
        //因为数字不重复,所以可以将数字作为键,索引作为值
        for(int i = 0; i < len; ++i){
            map.put(inorder[i], i);
        }
        //重建二叉树
        TreeNode root = buildTree(0, len, 0);
        return root;
    }

    public TreeNode buildTree(int i, int j, int k){
        //创建当前位置对应数组节点
        TreeNode node = new TreeNode(preorder[k]);
        //记录根节点位置
        int root = map.get(preorder[k]);
        //先序遍历根节点一般为下一个左根节点,所以执行加一操作,后面在判断是不是为左节点
        k++;
        //进行下一层根节点操作
        //判断是否有左根节点
        if(root > i){
            node.left = buildTree(i, root, k);
        }
        //判断是否有右节点
        if(1 + root < j && k+root-i < len){
            node.right = buildTree(root+1, j, k+root-i);
        }
        return node;
    }
}

题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

什巳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值