前序/后序与中序遍历序列构造二叉树构造二叉树

本文介绍了如何利用前序与中序遍历序列以及后序与中序遍历序列构造二叉树,主要通过LeetCode的105和106题进行解析。讲解了利用分治思想,通过找到根节点在中序遍历中的位置来划分左右子树,并递归或迭代地构建二叉树。
摘要由CSDN通过智能技术生成

从前序与中序遍历序列构造二叉树

Leetcode105 https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/

从后续与中序遍历序列构造二叉树

Leetcode106: https://leetcode-cn.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/

以105为例分析:本质利用分治的思想

  1. 前序中左起第一位1肯定是根结点,我们可以据此找到中序中根结点的位置rootin;
  2. 中序中根结点左边就是左子树结点,右边就是右子树结点,即[左子树结点,根结点,右子树结点], 我们就可以得出左子树结点个数为int left = rootin - leftin;
  3. 前序中结点分布应该是:[根结点,左子树结点,右子树结点];
  4. 根据前一步确定的左子树个数,可以确定前序中左子树结点和右子树结点的范围;
  5. 如果我们要前序遍历生成二叉树的话,下一层递归应该是:
    左子树:root->left = pre_order(前序左子树范围,中序左子树范围,前序序列,中序序列);;
    右子树:root->right = pre_order(前序右子树范围,中序右子树范围,前序序列,中序序列);。
  6. 每一层递归都要返回当前根结点root;

图示:

在这里插入图片描述

  1. 递归版本:
class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
            
            TreeNode root=find(0,preorder.length-1,0,inorder.length-1,preorder,inorder);
            return root;
          
    }
    public TreeNode find(int pre_left,int pre_right,int in_left,int in_right, int[] preorder,int[] inorder){
            //终止条件,前序数组大小为空
            if(pre_right<pre_left) return null;
            TreeNode root=new TreeNode(preorder[pre_left]);
            int index=0;
            //寻找根结点在中序数组的位置,这里可以用hashmap优化,不用每次遍历
            for(int i=in_left;i<=in_right;i++){
                  if(inorder[i]==root.val){
                      index=i;
                      break;
                  }
            }
            int len=index-in_left;
            //构造左子树
            root.left=find(pre_left+1,pre_left+len,in_left,index-1,preorder,inorder);
            //构造右子树
            root.right=find(pre_left+len+1,pre_right,index+1,in_right,preorder,inorder);
            return root;
    }
}

迭代版本:一般递归可利用栈实现迭代

public TreeNode buildTree(int[] preorder, int[] inorder) {
    if (preorder.length == 0) {
        return null;
    }
    Stack<TreeNode> roots = new Stack<TreeNode>();
    int pre = 0;
    int in = 0;
    //先序遍历第一个值作为根节点
    TreeNode curRoot = new TreeNode(preorder[pre]);
    TreeNode root = curRoot;
    roots.push(curRoot);
    pre++;
    //遍历前序遍历的数组
    while (pre < preorder.length) {
        //出现了当前节点的值和中序遍历数组的值相等,寻找是谁的右子树
        if (curRoot.val == inorder[in]) {
            //每次进行出栈,实现倒着遍历
            while (!roots.isEmpty() && roots.peek().val == inorder[in]) {
                curRoot = roots.peek();
                roots.pop();
                in++;
            }
            //设为当前的右孩子
            curRoot.right = new TreeNode(preorder[pre]);
            //更新 curRoot
            curRoot = curRoot.right;
            roots.push(curRoot);
            pre++;
        } else {
            //否则的话就一直作为左子树
            curRoot.left = new TreeNode(preorder[pre]);
            curRoot = curRoot.left;
            roots.push(curRoot);
            pre++;
        }
    }
    return root;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值