likes
comments
collection
share

根据前序、中序遍历构造二叉树 and 根据中序、后序遍历构造二叉树

作者站长头像
站长
· 阅读数 44

1. 根据一棵树的前序遍历与中序遍历构造二叉树

(ps:题目链接)105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)

  给你两个序列,preorderinorder , preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,构造出二叉树并返回其根节点。

  来看看二叉树的前序遍历与中序遍历的特点是什么。

前序遍历:

  前序遍历的第一个节点是二叉树的根节点,然后是左子树的节点,最后是右子树的节点。

根据前序、中序遍历构造二叉树 and  根据中序、后序遍历构造二叉树

中序遍历:

  中序遍历的前一部分是左子树的节点,中间是根节点,最后是右子树的节点。

根据前序、中序遍历构造二叉树 and  根据中序、后序遍历构造二叉树

  因为是同一个二叉树,所以这两种序列的左子树节、右子树节点是相同的,这时我们就可以通过递归的方式来创建这个二叉树。

  怎么递归呢?因为前序序列的第一个节点是根节点,我们拿到第一个节点然后在中序序列中找到该节点的位置,用该节点的左边来创建左子树、右边来创建右子树,然后以它们的子区间用相同的步骤来创建。

根据前序、中序遍历构造二叉树 and  根据中序、后序遍历构造二叉树

按照上面的思路,我们需要将区间的范围给表示出来,以方便递归:

根据前序、中序遍历构造二叉树 and  根据中序、后序遍历构造二叉树

//根据一棵树的前序遍历与中序遍历构造二叉树

//preorder为前序序列,inorder为后序序列。
public TreeNode buildTree(int[] preorder, int[] inorder) {
    //开始的区间是 前序:0~preorder.length  中序:0~inorder.length
    return buildTreeChild(preorder,0,preorder.length-1,inorder,0,inorder.length - 1);
}

public TreeNode buildTreeChild(int[] preorder,int preLeft,int preRight,int[] inorder,int inLeft,int inRight){
    //当没有子树的时候
    if(preLeft > preRight || inLeft > inRight){
        return null;
    }
    //创建根节点,preorder[preLeft] 为根节点
    TreeNode root = new TreeNode(preorder[preLeft]);
    //查找 中序序列中的根节点位置
    int rootIndex = findIndex(inorder,inLeft,inRight,preorder[preLeft]);

    //对左子树序列进行递归创建,连接左子树
    // 前序:(preLeft + 1,rootIndex - inLeft + preLeft) 中序:(inLeft,rootIndex - 1)
    root.left = buildTreeChild(preorder,preLeft + 1,rootIndex - inLeft + preLeft,inorder,inLeft,rootIndex - 1);
    //对右子树序列进行递归创建,连接右子树
    // 前序:(rootIndex - inLeft + preLeft + 1,preRight) 中序:(rootIndex + 1 ,inRight)
    root.right = buildTreeChild(preorder,rootIndex - inLeft + preLeft + 1,preRight,inorder,rootIndex + 1,inRight);
    return root;
}

//查找根节点在中序中的下标
public int findIndex(int[] inorder,int inLeft,int inRight,int val){
    for(int i = inLeft;i <= inRight;i++){
        if(inorder[i] == val){
            return i;
        }
    }
    return -1;
}

  这里的查找根节点在中序中的下标可以用哈希表来优化(可以去看官方答案),这里就不演示了。

2. 根据一棵树的中序遍历与后序遍历构造二叉树

(ps:题目链接)106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)

  跟上面的方法一模一样,只不过是位置换了一下。

根据前序、中序遍历构造二叉树 and  根据中序、后序遍历构造二叉树

  后序遍历就是最后一个节点为树的根节点,以此来在中序中寻找根节点的位置来划分左右子树。

public int findIndex(int[] inorder,int inLeft,int inRight,int val){
    for(int i = inLeft;i <= inRight;i++){
        if(inorder[i] == val){
            return i;
        }
    }
    return -1;
}


//根据一棵树的中序遍历与后序遍历构造二叉树
public TreeNode buildTree(int[] inorder, int[] postorder) {
    return buildTreeChild(inorder,0,inorder.length - 1,postorder,0,postorder.length - 1);
}
public TreeNode buildTreeChild(int[] inorder,int inLeft,int inRight,int[] postorder,int posLeft,int posRight){
    if(inLeft > inRight || posLeft > posRight){
        return null;
    }
    
    //查找 中序序列中的根节点位置
    int rootIndex = findIndex(inorder,inLeft,inRight,postorder[posRight]);
    //创建根节点
    TreeNode root = new TreeNode(postorder[posRight]);
    //对左子树序列进行递归创建,连接左子树
    root.left = buildTreeChild(inorder,inLeft,rootIndex - 1,postorder,posLeft,rootIndex - inLeft + posLeft- 1);
    //对右子树序列进行递归创建,连接右子树
    root.right = buildTreeChild(inorder,rootIndex + 1,inRight,postorder,rootIndex - inLeft + posLeft,posRight- 1);
    return root;
}

  当然,这里的查找中序序列中的根节点位置也可以用哈希,大家自己去试一试。

(ps:如有错误,请在评论区指出,谢谢🌹)

转载自:https://juejin.cn/post/7227491104886063165
评论
请登录