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());
    }
};
相关文章
|
13天前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
42 2
|
4天前
|
存储 算法
二叉树进阶-学会层序遍历助你一次刷完leetcode10道题
文章深入探讨了二叉树的层序遍历方法,并展示了如何通过队列实现层序遍历的算法逻辑,同时指出掌握层序遍历技巧可以帮助解决LeetCode上的多道相关题目。
二叉树进阶-学会层序遍历助你一次刷完leetcode10道题
|
4天前
|
算法 Java
LeetCode第94题二叉树的中序遍历
文章介绍了LeetCode第94题"二叉树的中序遍历"的解法,使用递归实现了中序遍历的过程,遵循了"左根右"的遍历顺序,并提供了清晰的Java代码实现。
LeetCode第94题二叉树的中序遍历
|
13天前
|
Python
【Leetcode刷题Python】50. Pow(x, n)
本文介绍了LeetCode第50题"Pow(x, n)"的解法,题目要求实现计算x的n次幂的函数,文章提供了递归分治法的详细解析和Python实现代码。
11 1
|
13天前
|
算法 Python
【Leetcode刷题Python】73. 矩阵置零
本文介绍了LeetCode第73题的解法,题目要求在给定矩阵中将所有值为0的元素所在的行和列全部置为0,并提供了一种原地算法的Python实现。
13 0
【Leetcode刷题Python】73. 矩阵置零
|
11天前
|
存储 算法 Java
LeetCode经典算法题:二叉树遍历(递归遍历+迭代遍历+层序遍历)以及线索二叉树java详解
LeetCode经典算法题:二叉树遍历(递归遍历+迭代遍历+层序遍历)以及线索二叉树java详解
31 0
|
11天前
|
算法 Java
LeetCode初级算法题:子数组最大平均数+二叉树的最小深度+最长连续递增序列+柠檬水找零
LeetCode初级算法题:子数组最大平均数+二叉树的最小深度+最长连续递增序列+柠檬水找零
23 0
|
13天前
|
Python
【Leetcode刷题Python】1467. 两个盒子中球的颜色数相同的概率
本文介绍了LeetCode第50题"Pow(x, n)"的解法,题目要求实现计算x的n次幂的函数,文章提供了递归分治法的详细解析和Python实现代码。
13 0
|
13天前
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
27 6
|
13天前
|
Python
【Leetcode刷题Python】剑指 Offer 26. 树的子结构
这篇文章提供了解决LeetCode上"剑指Offer 26. 树的子结构"问题的Python代码实现和解析,判断一棵树B是否是另一棵树A的子结构。
28 4