LC.105 | 从前序与中序遍历序列构造二叉树 | 树 | 递归分治

输入:两个整数数组 preorder(前序遍历)和 inorder(中序遍历)

要求:根据这两个序列构造二叉树 preorder 和 inorder 均无重复元素

输出:构造出的二叉树的根节点


思路:这道题乍一看有些棘手,但既然涉及到 “构造二叉树”,第一时间就应该联想到 递归(分治法)

我们可以试着模拟人脑还原树的过程:

  1. 定位根节点:拿到题目,我们怎么知道谁是根?显然,前序遍历 告诉了我们“谁是头”(第一个元素)。

  2. 划分势力范围:知道根是谁后,去 中序遍历 里找到它的位置。这一找,瞬间就清晰了——根节点左边的所有元素属于 左子树,右边的所有元素属于 右子树

  3. 递归的传递:既然父节点能这么分,子节点当然也能这么分。这是一个典型的“子问题”结构。

  4. 确立返回值:题目要求返回整棵树的 TreeNode*,那么我们的递归函数也应当返回当前子树的根节点 TreeNode*

一句话总结:前序遍历负责 “提头”(确定根),中序遍历负责 “切分”(确定左右子树长度)。把这个逻辑想通了,递归函数的写法也就呼之欲出了。

利用前序和中序遍历的特性进行递归拆解:

  1. 找根节点前序遍历的第一个元素 pre[0] 一定是当前的根节点

  2. 切分左右子树:拿着这个根节点的值,去中序遍历里找它的位置。

    • 中序序列中,根节点左边的所有数构成了左子树

    • 中序序列中,根节点右边的所有数构成了右子树

  3. 递归构建

    • 根据中序遍历中算出的左子树长度,在前序遍历中也能切分出对应的左子树部分(紧跟在根节点后面)。

    • 既然拿到了左右子树各自的 preorderinorder 序列,就可以递归生成左节点和右节点。


复杂度:

        时间复杂度:O(N^2) //使用了vector的拷贝 进阶写法肯定是引用而不是拷贝

        空间复杂度:O(N^2) //使用了vector的拷贝 进阶写法肯定是引用而不是拷贝


class Solution {

public:

    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {

        return tree(preorder, inorder);

    }

    TreeNode* tree(vector<int> pre, vector<int> in) {

        if (pre.empty()) {

            return nullptr;

        }



        TreeNode* tmp = new TreeNode(pre[0]);



        vector<int> preleft,inleft,preright,inright;



        int i = 0;

        for (; i < in.size(); i++) {

            if (in[i] == pre[0]) {

                break;

            }

            inleft.push_back(in[i]);

        }

        i += 1;

        for (; i < in.size(); i++) {

            inright.push_back(in[i]);

        }



        int j = 1;

        for (int k = 0; k < inleft.size(); k++) {

            preleft.push_back(pre[j++]);

        }

        for (int k = 0; k < inright.size(); k++) {

            preright.push_back(pre[j++]);

        }



        tmp->left = tree(preleft, inleft);

        tmp->right = tree(preright, inright);



        return tmp;

    }

};

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值