leetcode106从中序与后序遍历序列构造二叉树刷题打卡

简介: leetcode106从中序与后序遍历序列构造二叉树刷题打卡

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

题目描述:

给定两个整数数组 inorderpostorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树

容易理解的做法

题解思路:

由中序遍历序列与后序遍历序列或者与前序遍历序列可以唯一的确定一颗二叉树,本题给出的是中序与后序,则由后序的最后一个结点可以唯一的确定根节点,然后就可以找出中序中的根节点,在中序中,根节点的左右子数组分别代表根节点的左右子树序列,可以使用递归来解

递归三部曲:

  • 确定参数与返回值
  • 参数需要一个前序子序列和一个后序子序列
  • 返回值返回TreeNode*来让主函数接收
  • 确定终止条件
  • 首先判断左右子序列是否为空,防止给定的左右子序列过短而直接传进来的数组为0而导致错误,为空的话就直接返回NULL
  • 例如:[2, 1] \ [2, 1]
  • 然后可以为了缩短时间可以在root创建之后加一个叶子节点的判断,如果左右子序列只有一个值了,也就是访问到叶子节点了,则直接返回root
  • 确定本层逻辑
  • 在中序中找到切割点的索引值,然后遵循一个相同的原则来切割数组,我遵循的是左闭右开的原则,故有以下代码
int i = 0;
for(; i < inorder.size(); i++){
  if(inorder[i] == postval) break;
}
// 遵循左闭右开
vector<int> leftleft(inorder.begin(), inorder.begin() + i);
vector<int> leftright(inorder.begin() + i + 1, inorder.end());  // 加一是为了舍弃中间的根节点元素
postorder.pop_back(); // 去掉根节点的值
vector<int> rightleft(postorder.begin(), postorder.begin() + leftleft.size());
vector<int> rightright(postorder.begin() + leftleft.size(), postorder.end());
  • 然后令左右子树分别等于递归的值
root->left = constructT(leftleft,rightleft);
root->right = constructT(leftright,rightright);

完整代码

class Solution {
public:
    TreeNode* constructT(vector<int> & inorder, vector<int> & postorder){
        if(inorder.size() == 0 || postorder.size() == 0) return nullptr;
        int postval = postorder[postorder.size()-1];
        TreeNode *root = new TreeNode(postval);
        int i = 0;
        for(; i < inorder.size(); i++){
            if(inorder[i] == postval) break;
        }
        // 遵循左闭右开
        vector<int> leftleft(inorder.begin(), inorder.begin() + i);
        vector<int> leftright(inorder.begin() + i + 1, inorder.end());  // 加一是为了舍弃中间的根节点元素
        postorder.pop_back();
        vector<int> rightleft(postorder.begin(), postorder.begin() + leftleft.size());
        vector<int> rightright(postorder.begin() + leftleft.size(), postorder.end());
        root->left = constructT(leftleft,rightleft);
        root->right = constructT(leftright,rightright);
        return root;
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        TreeNode *result = constructT(inorder, postorder);
        return result;
    }
};
优化解法

上述方法空间复杂度太高了,可以加参数来通过索引下标来操作分割

  • 参数与返回值
  • 参数多加了四个参数,分别是中序序列的首尾索引(2、3参数)和后序序列的首尾索引(5、6)参数
  • TreeNode* constructT(vector<int>& inorder,int inorderbegin, int inorderend, vector<int>& postorder, int postorderbegin, int postorderend)
  • 返回值还是TreeNode*便于**“主函数”**接收
  • 终止条件
  • 空判断与叶子节点判断
  • 空判断:当任一子序列的收尾索引相等时返回nullptr或者是NULL
  • 叶子判断:当任一子序列的收尾索引相差1时提前结束本层递归返回root
  • 本层逻辑
  • 找切割点与上面的方法相同,都是for循环遍历
  • 不同点在于切割的是索引不是数组,inorderpostorder数组在整个过程一直不会变,变的是传入的索引,利用此来控制切割的数组

完整代码

class Solution {
public:
    TreeNode* constructT(vector<int>& inorder,int inorderbegin, int inorderend, vector<int>& postorder, int postorderbegin, int postorderend){
        if(inorderbegin == inorderend) return nullptr;
        int postorderval = postorder[postorderend - 1];
        TreeNode* root = new TreeNode(postorderval);
        if(inorderend - inorderbegin == 1) return root;
        // 切割点(cut point)
        int cp;
        for(cp = inorderbegin; cp < inorderend; cp++){
            if(inorder[cp] == postorderval) break;
        }
        // 前序左子序列
        int inorderleftbegin = inorderbegin;
        int inorderleftend = cp;
        // 前序右子序列
        int inorderrightbegin = cp + 1;
        int inorderrightend = inorderend;
        // 前序左子序列的长度
        int diff = inorderleftend - inorderleftbegin;
        // 后序左子序列
        int postorderleftbegin = postorderbegin;
        int postorderleftend = postorderbegin + diff;
        // 后续右子序列
        int postorderrightbegin = postorderbegin + diff;
        int postorderrightend = postorderend - 1;
        root->left = constructT(inorder, inorderleftbegin, inorderleftend, postorder, postorderleftbegin, postorderleftend);
        root->right = constructT(inorder, inorderrightbegin, inorderrightend, postorder, postorderrightbegin, postorderrightend);
        return root;
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if(inorder.size() == 0 || postorder.size() == 0) return nullptr;
        return constructT(inorder, 0, inorder.size(), postorder, 0, postorder.size());
    }
};
相关文章
|
22天前
|
机器学习/深度学习 人工智能 自然语言处理
280页PDF,全方位评估OpenAI o1,Leetcode刷题准确率竟这么高
【10月更文挑战第24天】近年来,OpenAI的o1模型在大型语言模型(LLMs)中脱颖而出,展现出卓越的推理能力和知识整合能力。基于Transformer架构,o1模型采用了链式思维和强化学习等先进技术,显著提升了其在编程竞赛、医学影像报告生成、数学问题解决、自然语言推理和芯片设计等领域的表现。本文将全面评估o1模型的性能及其对AI研究和应用的潜在影响。
16 1
|
1月前
【LeetCode 43】236.二叉树的最近公共祖先
【LeetCode 43】236.二叉树的最近公共祖先
19 0
|
1月前
【LeetCode 38】617.合并二叉树
【LeetCode 38】617.合并二叉树
14 0
|
1月前
【LeetCode 37】106.从中序与后序遍历构造二叉树
【LeetCode 37】106.从中序与后序遍历构造二叉树
17 0
|
1月前
【LeetCode 34】257.二叉树的所有路径
【LeetCode 34】257.二叉树的所有路径
17 0
|
2月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
3月前
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
57 6
|
3月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
114 2
|
2月前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
|
3月前
|
索引 Python
【Leetcode刷题Python】从列表list中创建一颗二叉树
本文介绍了如何使用Python递归函数从列表中创建二叉树,其中每个节点的左右子节点索引分别是当前节点索引的2倍加1和2倍加2。
57 7