【力扣】根据二叉树的前序和中序遍历结果还原该二叉树(以及后序和中序还原)

一 前序和中序还原二叉树

连接:根据二叉树的前序和中序遍历结果还原该二叉树
在这里插入图片描述

思路是这样的:

  • 这个算法的目的是根据前序遍历和中序遍历的结果,重建一棵二叉树。
  • 前序遍历的特点是,第一个元素一定是根节点,后面的元素是左子树和右子树的前序遍历。
  • 中序遍历的特点是,根节点在左子树和右子树的中间,左边的元素是左子树的中序遍历,右边的元素是右子树的中序遍历。
  • 因此,我们可以利用前序遍历确定根节点,然后在中序遍历中找到根节点的位置,从而分割出左子树和右子树的区间。
  • 然后,我们递归地对左子树和右子树进行同样的操作,直到区间为空或者只有一个元素为止。
  • 最后,我们返回重建好的二叉树的根节点。

代码并加上了注释:

class Solution {
    
     
public: 
  //后序确定根 
  //中序分割左右区间 
  TreeNode* _buildTree(vector<int>& inorder, vector<int>& postorder, int& posti, int ibegin, int iend) {
    
     
    if (ibegin > iend) return nullptr; //如果中序区间为空,返回空指针
    TreeNode* root = new TreeNode(postorder[posti]); //创建根节点,值为后序遍历的最后一个元素
    //分割左右子区间 
    int rooti = ibegin; //找到根节点在中序遍历中的位置
    while (rooti <= iend) {
    
     
      if (inorder[rooti] == postorder[posti]) break; //找到了,跳出循环
      else rooti++; //没找到,继续向右移动
    } 
    --posti; //后序遍历的索引向前移动一位
    root->right = _buildTree(inorder, postorder, posti, rooti+1, iend); //递归构建右子树,中序区间为[rooti+1, iend]
    root->left = _buildTree(inorder, postorder, posti, ibegin, rooti-1); //递归构建左子树,中序区间为[ibegin, rooti-1]
    return root; //返回根节点
  } 
  TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
    
     
    int i = postorder.size()-1; //初始化后序遍历的索引为最后一位
    return _buildTree(inorder, postorder, i, 0, inorder.size()-1); //调用辅助函数,中序区间为[0, inorder.size()-1]
  } 
};

二 后序和中序还原二叉树

如果是后序和中序让你来还原二叉树呢?
链接:后序和中序还原二叉树

还是上面那种思路,只不过这次要先递归构建右子树,这是因为后序遍历的特点是,最后一个元素是根节点,前面的元素是左子树和右子树的后序遍历,而且右子树在左子树的后面。所以,我们要先递归构建右子树,然后再构建左子树,这样才能保证后序遍历的索引正确

在这里插入图片描述

  • 后序遍历的最后一个元素是二叉树的根节点。
  • 在中序遍历中找到根节点的位置,根节点左边的序列是左子树的中序遍历,右边的序列是右子树的中序遍历。
  • 在后序遍历中找到对应的左子树和右子树的序列,左子树的长度和中序遍历中左子树的长度相同,右子树也一样。
  • 递归地对左子树和右子树重复上述步骤,直到后序遍历或中序遍历为空。

例如,给定后序遍历 [9, 15, 7, 20, 3] 和中序遍历 [9, 3, 15, 20, 7],还原二叉树的过程如下:

  • 后序遍历的最后一个元素是 3,它是二叉树的根节点。
  • 在中序遍历中找到 3 的位置,它左边的序列 [9] 是左子树的中序遍历,右边的序列 [15, 20, 7] 是右子树的中序遍历。
  • 在后序遍历中找到对应的左子树和右子树的序列,左子树只有一个元素 [9],右子树有三个元素 [15, 7, 20]。
  • 对左子树递归地还原二叉树,由于后序遍历和中序遍历只有一个元素,所以左子节点就是 9。
  • 对右子树递归地还原二叉树,由于后序遍历和中序遍历都不为空,重复上述步骤。

代码:

class Solution {
    
     
public: 
  //后序确定根 
  //中序分割左右区间 
  TreeNode* _buildTree(vector<int>& inorder, vector<int>& postorder, int& posti, int ibegin, int iend) {
    
     
    if (ibegin > iend) return nullptr; //如果中序区间为空,返回空指针
    TreeNode* root = new TreeNode(postorder[posti]); //创建根节点,值为后序遍历的最后一个元素
    //分割左右子区间 
    int rooti = ibegin; //找到根节点在中序遍历中的位置
    while (rooti <= iend) {
    
     
      if (inorder[rooti] == postorder[posti]) break; //找到了,跳出循环
      else rooti++; //没找到,继续向右移动
    } 
    --posti; //后序遍历的索引向前移动一位
    root->right = _buildTree(inorder, postorder, posti, rooti+1, iend); //递归构建右子树,中序区间为[rooti+1, iend]
    root->left = _buildTree(inorder, postorder, posti, ibegin, rooti-1); //递归构建左子树,中序区间为[ibegin, rooti-1]
    return root; //返回根节点
  } 
  TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
    
     
    int i = postorder.size()-1; //初始化后序遍历的索引为最后一位
    return _buildTree(inorder, postorder, i, 0, inorder.size()-1); //调用辅助函数,中序区间为[0, inorder.size()-1]
  } 
};

本节完

猜你喜欢

转载自blog.csdn.net/weixin_62676865/article/details/130466686