【算法】递归+深搜+哈希表:889.根据前序和后序遍历构造二叉树

目录

1、题目链接

相似题目:

2、题目

​3、解法(针对无重复值,哈希表+递归)

函数头-----找出重复子问题

函数体---解决子问题

4、代码


1、题目链接

889.根据前序和后序遍历构造二叉树(LeetCode)

相似题目:

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

106.从中序与后序遍历序列构造二叉树(LeetCode)

2、题目

3、解法(针对无重复值,哈希表+递归)

前序:根节点、左子树、右子树
后序:左子树、右子树、根节点

二叉树的根节点一定是前序遍历的第一个节点,也是后序遍历的最后一个节点。

接下来,我们需要确定二叉树的左子树范围和右子树范围。

首先,仅凭前序和后序,得不到唯一的二叉树。结果可能有多个。

没有中序遍历的情况下,无法区分哪些节点属于左子树,哪些属于右子树。

第二个元素我们默认他是左子树的根节点。

函数头-----找出重复子问题

深搜函数头:preorder前序数组,

root :根节点在前序的下标

left:根节点所在子树的左边界

right:根节点所在子树的右边界

复制代码
TreeNode* dfs(const vector<int>& preorder, int root, int left, int right)

函数体---解决子问题

哈希表 hash,它存储了后序遍历中每个节点的位置。在函数的开头,我们可以找到任意节点在后序遍历中的位置。

  1. 如果 left >right ,说明范围为空,直接返回空节点。
  2. 否则,我们构造一个新的节点 node ,它的值为前序遍历中的第一个节点的值,也就是 preorder[root]。
  3. 如果 left 等于 right ,说明 root 没有左子树也没有右子树,直接返回 root。
  4. 否则,左子树的根节点的值为 preorder[ root + 1],我们在后序遍历中找到 preorder[ root + 1] 的位置,记为 pos_root。
    1. 那么左子树的节点个数 left_size = pos_root − left + 1,由此可知左子树后序遍历中的范围是 [left , pos_root ],右子树在后序遍历中的范围是 [pos_root + 1, right −1]。
  5. 知道了左右子树的范围,我们就可以递归地重建左右子树,然后将左右子树的根节点分别作为 node 的左右子节点。最后返回 node。
cpp 复制代码
        if (left > right)
            return NULL;

        TreeNode* node = new TreeNode(preorder[root]);//构建根节点
       
        //非常重要!!!影响整个代码的通过
        //root 没有左子树也没有右子树,直接返回 root。
        if (left == right)
            return node;

        int pos_root = hash[preorder[root + 1]];    //左子树的root在后序的下标
        
        int left_size = pos_root - left + 1; //左子树结点数(含root)
        int right_root = root + left_size + 1;//右子树根节点在前序中的下标

        node->left = dfs(preorder, root+1, left, pos_root);
        node->right = dfs(preorder, right_root, pos_root + 1, right - 1);

4、代码

cpp 复制代码
class Solution {

    //仅仅依靠前序、后序,会有存在多个二叉树
public:
    unordered_map<int, int> hash;

    //root 在pre的下标
    TreeNode* dfs(const vector<int>& preorder, int root, int left, int right)
    {
        if (left > right)
            return NULL;

        TreeNode* node = new TreeNode(preorder[root]);//构建根节点
       
        //非常重要!!!影响整个代码的通过
        //root 没有左子树也没有右子树,直接返回 root。
        if (left == right)
            return node;

        int pos_root = hash[preorder[root + 1]];    //左子树的root在后序的下标
        
        int left_size = pos_root - left + 1; //左子树结点数(含root)
        int right_root = root + left_size + 1;//右子树根节点在前序中的下标

        node->left = dfs(preorder, root+1, left, pos_root);
        node->right = dfs(preorder, right_root, pos_root + 1, right - 1);

        return node;
    }

    TreeNode* constructFromPrePost(vector<int>& preorder, vector<int>& postorder) {
        //postorder填充hash
        for (int i = 0; i < postorder.size(); i++)
        {
            hash[postorder[i]] = i;
        }

        return dfs(preorder, 0, 0, postorder.size() - 1);
    }
};
相关推荐
hn小菜鸡2 小时前
LeetCode 377.组合总和IV
数据结构·算法·leetcode
Deepoch2 小时前
Deepoc 大模型:无人机行业的智能变革引擎
人工智能·科技·算法·ai·动态规划·无人机
heimeiyingwang9 天前
【深度学习加速探秘】Winograd 卷积算法:让计算效率 “飞” 起来
人工智能·深度学习·算法
时空自由民.9 天前
C++ 不同线程之间传值
开发语言·c++·算法
ai小鬼头9 天前
AIStarter开发者熊哥分享|低成本部署AI项目的实战经验
后端·算法·架构
小白菜3336669 天前
DAY 37 早停策略和模型权重的保存
人工智能·深度学习·算法
zeroporn9 天前
以玄幻小说方式打开深度学习词嵌入算法!! 使用Skip-gram来完成 Word2Vec 词嵌入(Embedding)
人工智能·深度学习·算法·自然语言处理·embedding·word2vec·skip-gram
亮亮爱刷题9 天前
飞往大厂梦之算法提升-7
数据结构·算法·leetcode·动态规划
_周游9 天前
【数据结构】_二叉树OJ第二弹(返回数组的遍历专题)
数据结构·算法
双叶8369 天前
(C语言)Map数组的实现(数据结构)(链表)(指针)
c语言·数据结构·c++·算法·链表·哈希算法