leetcode 105从前序和中序遍历序列构造二叉树

复制代码
class Solution {
public:

    // 保存:节点值 -> 中序遍历下标
    // 方便快速找到根节点在中序中的位置
    unordered_map<int,int> index;


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

        int n = preorder.size();

        // 建立中序哈希表
        for(int i = 0; i < n; i++){
            index[inorder[i]] = i;
        }

        // 递归构造整棵树
        return build(preorder, inorder,
                     0, n - 1,
                     0, n - 1);
    }


    /*
        pre_left ~ pre_right:
            当前树在前序遍历中的范围

        in_left ~ in_right:
            当前树在中序遍历中的范围
    */
    TreeNode* build(vector<int>& preorder,
                    vector<int>& inorder,
                    int pre_left,
                    int pre_right,
                    int in_left,
                    int in_right){


        // 当前范围没有节点
        if(pre_left > pre_right){
            return nullptr;
        }


        // 前序第一个节点一定是根节点
        int pre_root = pre_left;


        // 找到根节点在中序中的位置
        int in_root = index[preorder[pre_root]];


        // 创建当前根节点
        TreeNode* root = new TreeNode(preorder[pre_root]);


        // 中序中根节点左边就是左子树
        // 计算左子树节点数量
        int left_size = in_root - in_left;


        // 构造左子树
        root->left = build(preorder,
                           inorder,
                           pre_left + 1,
                           pre_left + left_size,
                           in_left,
                           in_root - 1);


        // 构造右子树
        root->right = build(preorder,
                            inorder,
                            pre_left + left_size + 1,
                            pre_right,
                            in_root + 1,
                            in_right);


        // 返回当前子树的根节点
        return root;
    }
};

核心思路总结

这题只需要记住三句话:

1. 前序找根

因为:

复制代码
前序:根 -> 左 -> 右

所以:

复制代码
preorder[pre_left]

就是当前根节点。


2. 中序分左右

因为:

复制代码
中序:左 -> 根 -> 右

找到根的位置:

复制代码
in_root = index[root]

那么:

复制代码
in_root左边 = 左子树
in_root右边 = 右子树

3. 递归构造

当前节点:

复制代码
root = new TreeNode(...)

然后相信递归:

复制代码
root->left = build(...);
root->right = build(...);

返回:

复制代码
return root;

易错点

① 左子树数量

复制代码
int left_size = in_root - in_left;

不是:

复制代码
in_right - in_root

因为这里只求左子树。


② 左子树前序范围

复制代码
pre_left + 1

为什么?

因为:

复制代码
preorder:
根 左 左 左
↑
已经被拿走

所以跳过根。


③ 右子树前序起点

复制代码
pre_left + left_size + 1

因为:

跳过:

复制代码
根节点 + 左子树

④ 递归返回值

一定:

复制代码
return root;

因为父节点需要拿到:

复制代码
root->left = 左子树根
root->right = 右子树根

这题和你刚刚学的 flatten 本质一样:

flatten

相信递归处理左右子树,我修改当前节点。

建树:

相信递归返回左右子树,我连接当前节点。

你现在学二叉树递归,重点就是抓住这个模式。

相关推荐
一直C1 小时前
【数据结构】哈希表+算法复杂度与经典排序查找(C语言)
java·linux·开发语言·数据结构·算法·ubuntu·散列表
淡海水1 小时前
04-02-哈希-Dictionary-TKey-TValue-上-核心数据结构
数据结构·算法·c#·哈希算法·编译·字典·dictionary
戴西软件1 小时前
国内有哪些数据轻量化格式转换软件?
数据库·算法·安全·信息可视化·自动化·rpa
老洋葱Mr_Onion1 小时前
【C++】CSP-J初赛模拟卷七错题整理(作者自用)
c++·算法·深度优先
Nil2082 小时前
leetcode 114二叉树展开为链表
leetcode·链表·深度优先
土星云SaturnCloud2 小时前
Real-ESRGAN超分辨率算法原理与边缘侧部署实践
服务器·算法·ai·边缘计算·real-esrgan
cz07102 小时前
hot100_搜索二维矩阵 II
算法·leetcode
疯狂打码的少年2 小时前
【数据结构】板块总结 + 下期预告(数据库技术)
数据结构·笔记·算法
郝学胜_神的一滴2 小时前
Effective Python 条款 2:遵循 PEP 8 编码风格,写出高质量 Python 代码
python·算法