剑指Offer(7)重建二叉树

目录

重建二叉树

描述

示例1

示例2

限制

数据结构

方法一:递归

方法二:迭代(待补充)


重建二叉树

描述

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

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

示例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

数据结构

public class TreeNode {
    public int val = 0;
    public TreeNode left = null;
    public TreeNode right = null;
    
    public TreeNode(int val){
        this.val=val;
    }
}

方法一:递归

首先我们根据先序遍历下标0的元素为根节点这个特点,将中序遍历可以分为左子树的元素和右子树的元素,然后反过来将先序遍历分为左右子树,这样不断地重建子树,利用递归求解。

class Solution {
    private Map<Integer,Integer> indexMap;

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        int n=inorder.length;
        indexMap=new HashMap<>();
        for (int i = 0; i < n; i++) {
            indexMap.put(inorder[i],i);
        }
        return rebuildTree(preorder,inorder,0,n-1,0,n-1);
    }

    public TreeNode rebuildTree(int[] preorder, int[] inorder, int preorder_left,int preorder_right,int inorder_left,int inorder_right){
        if (preorder_left>preorder_right){
            return null;
        }

        int rootIndex=indexMap.get(preorder[preorder_left]);//根节点在中序遍历中的下标

        TreeNode root=new TreeNode(preorder[preorder_left]);//构造根节点
        int leftsize=rootIndex-inorder_left;//左子树的元素个数
        root.left=rebuildTree(preorder,inorder,preorder_left+1,preorder_left+leftsize,inorder_left,rootIndex-1);//递归构造左子树
        root.right=rebuildTree(preorder,inorder,preorder_left+leftsize+1,preorder_right,rootIndex+1,inorder_right);//递归构造右子树
        return root;
    }
}

方法二:迭代(待补充)

迭代使用的思想比较巧妙,也就是比较难想。

对于前序遍历中任意两个连续节点uv,根据前序遍历的特点,uv只存在两种关系:

  1. v是u的左儿子:这是因为在遍历到根节点u之后,下一个遍历就是其左儿子,即v节点。
  2. u没有左儿子:如果u没有左儿子,那么v就是u或者u的某个祖先节点的右儿子。因为u没有左儿子,那么前序遍历会接着访问右儿子,如果右儿子也没有那么就向上回溯访问第一个有右儿子的节点。

猜你喜欢

转载自blog.csdn.net/weixin_39478524/article/details/120492801