【leetcode】105 从前序与中序遍历序列构造二叉树(二叉树)

博客围绕根据一棵树的前序遍历与中序遍历构造二叉树展开。指出前序/后序+中序序列可唯一确定一棵二叉树,分析了前序和中序的特点,给出递归建树思路,还提及时间复杂度为O(n),空间复杂度为O(1),最后提到代码优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/

题目描述

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

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

例如,给出

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

返回如下的二叉树:

  3
   / \
  9  20
    /  \
   15   7

思路

首先要知道一个结论,前序/后序+中序序列可以唯一确定一棵二叉树,所以自然而然可以用来建树。

看一下前序和中序有什么特点,前序1,2,4,7,3,5,6,8 ,中序4,7,2,1,5,3,8,6

有如下特征:

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

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

代码

class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(preorder.empty()||inorder.empty()||preorder.size() != preorder.size()) return nullptr;

        int rootVal = preorder.front(), leftLen = 0;
        while(inorder[leftLen]!= rootVal) ++ leftLen;
        int rightLen = preorder.size() - leftLen -1;
        TreeNode *root = new TreeNode(rootVal);
        vector<int> preorderLeft(preorder.begin()+1, preorder.begin()+1+leftLen);
        vector<int> preorderRight(preorder.end() - rightLen, preorder.end());
        vector<int> inorderLeft(inorder.begin(), inorder.begin() + leftLen);
        vector<int> inorderRight(inorder.end() - rightLen, inorder.end());
        root->left = buildTree(preorderLeft, inorderLeft);
        root->right = buildTree(preorderRight, inorderRight);
        return root;
    }
};

在这里插入图片描述

优化一下,只传preorder和inorder的引用,以及对应的坐标

class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(preorder.empty()||inorder.empty()||preorder.size() != preorder.size()) return nullptr;
        return buildTreeCore(0, inorder.size()-1, 0, inorder.size()-1, preorder, inorder);
    }

    TreeNode* buildTreeCore(int preLeft, int preRight, int inLeft, int inRight, vector<int>& preorder, vector<int>& inorder){
        if(preLeft>preRight || inLeft>inRight) return nullptr;
        TreeNode* root = new TreeNode(preorder[preLeft]);   // 根节点
        int inRoot = inLeft;                                // 中序遍历中根节点的位置
        while (inRoot <= inRight && inorder[inRoot] != preorder[preLeft]) ++ inRoot;
        int leftLen = inRoot - inLeft;                      // 左子树的长度,也是根节点在中序中的位置
        root->left = buildTreeCore(preLeft+1, preLeft + leftLen, inLeft, inRoot-1, preorder,inorder);
        root->right = buildTreeCore(preLeft+leftLen+1, preRight, inRoot+1, inRight, preorder,inorder);
        return root;
    }
};

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值