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

这篇博客探讨了如何使用递归和迭代方法从给定的前序和中序序列构建二叉树。首先介绍了递归解法,通过找到前序序列的根节点并利用中序序列定位子序列,递归构造左右子树。接着,解释了迭代解法,通过维护一个栈来构建树结构,依据中序序列的特性不断寻找左孩子和祖先的右孩子。这两种方法都有效地解决了二叉树的构建问题。
摘要由CSDN通过智能技术生成

题目

递归

观察发现前序序列的首位为根,然后需要从中序序列中找到该点,这样就得到了两个前序和中序的子序列,递归即可求解。

class Solution {
public:
    TreeNode* Recursion(vector<int>& preorder, vector<int>& inorder, int preorder_left, int preorder_right, int inorder_left, int inorder_right) {
        // 结束条件
        if(preorder_left > preorder_right)
            return nullptr;
        // 找到前序序列的根
        int preorder_root = preorder_left;
        // 找到中序序列的根
        int inorder_root = index[preorder[preorder_root]];
        // 构造当前序列的根节点
        TreeNode *root = new TreeNode(preorder[preorder_root]);
        // 计算一下左子树的大小
        int left_subtree_size = inorder_root - inorder_left;
        // 构造左子树
        root->left = Recursion(preorder, inorder, preorder_left + 1, preorder_left + left_subtree_size, inorder_left, inorder_root - 1);
        // 构造右子树
        root->right = Recursion(preorder, inorder, preorder_left + left_subtree_size + 1, preorder_right, inorder_root + 1, inorder_right);
        return root;
    }

    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int n = preorder.size();
        // 构造hash快速寻找中序序列的根
        for(int i = 0; i < n; ++i)
            index[inorder[i]] = i;
        // 递归
        return Recursion(preorder, inorder, 0, n - 1, 0, n - 1);
    }

private:
    unordered_map<int, int> index;
};

迭代

迭代的思想很有趣,观察先序序列,可以发现相邻两元素的关系只有两种情况:

  • 后者是前者的左孩子;
  • 后者是前者某个祖先的右孩子;

再根据中序序列的特点,可以发现一棵树的最左结点必然是中序序列的最左节点,那么就可以不断对树构造左孩子来寻找中序序列的最左结点,来构造树。

class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        // 特判空树
        if(!preorder.size())
            return nullptr;
        // 构造根
        TreeNode *root = new TreeNode(preorder[0]);
        // 用栈来存储所有根(父亲)
        stack<TreeNode*> stk;
        stk.push(root);
        // 顺序遍历中序序列
        int inorderIndex = 0;
        for(int i = 1; i < preorder.size(); ++i) {
            // 判断当前节点是否与中序序列的当前值相同
            TreeNode *node = stk.top();
            // 若不同则表示该节点仍有左孩子
            if(node->val != inorder[inorderIndex]) {
                node->left = new TreeNode(preorder[i]);
                stk.push(node->left);
            }
            // 若相同表示该节点再无左孩子,此时开始寻找祖先的右孩子
            else {
                // 将祖先中无右孩子的点出栈
                while(!stk.empty() && stk.top()->val == inorder[inorderIndex]) {
                    node = stk.top();
                    stk.pop();
                    inorderIndex++;
                }
                // 把右孩子给当前的根
                node->right = new TreeNode(preorder[i]);
                stk.push(node->right);
            }
        }
        return root;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

BeZer0

打赏一杯奶茶支持一下作者吧~~

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

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

打赏作者

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

抵扣说明:

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

余额充值