二叉树_题目27:105. 从前序与中序遍历序列构造二叉树

138 阅读4分钟

题目27:105. 从前序与中序遍历序列构造二叉树

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

同类题目

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

前置知识

题目描述

给定两个整数数组 preorderinorder ,其中 preorder 是二叉树的先序遍历inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

示例 1:

 输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
 输出: [3,9,20,null,null,15,7]

示例 2:

 输入: preorder = [-1], inorder = [-1]
 输出: [-1]

提示:

  • 1 <= preorder.length <= 3000
  • inorder.length == preorder.length
  • -3000 <= preorder[i], inorder[i] <= 3000
  • preorderinorder无重复 元素
  • inorder 均出现在 preorder
  • preorder 保证 为二叉树的前序遍历序列
  • inorder 保证 为二叉树的中序遍历序列

思路分析

递归

本题主要的是左右子树的的坐标确定

前序

  • 左子树坐标范围为 pstart + 1, pstart + left_len
  • 右子树坐标范围为pstart + left_len + 1, pend

中序

  • 左子树坐标范围为 istart,loc-1
  • 右子树坐标范围为loc + 1,iend

loc为中序中定位的根节点位置,pstart 为前序起始坐标,pend 为前序结束坐标,istart为中序起始坐标,iend 为中序结束坐标。

程序代码

方法一

 // https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/description/
 // 105. 从前序与中序遍历序列构造二叉树
 #include<iostream>
 #include<vector>
 #include<unordered_map>
 using namespace std;
 ​
 struct TreeNode {
     int val;
     TreeNode *left;
     TreeNode *right;
     TreeNode() : val(0), left(nullptr), right(nullptr) {}
     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 };
 class Solution {
 private:
     // 使用hash表构建中序排列遍历中元素的位置
     unordered_map<int,int> umap;
 public:    
     TreeNode* createTree(vector<int>& preorder,int pstart ,int pend,vector<int>& inorder,int istart,int iend)
     {
         if(istart > iend)
         {
             return nullptr;
         }
 ​
         // 构建当前节点
         TreeNode *cur = new TreeNode(preorder[pstart]);
         
         // 找到头结点在中序中的位置后,将中序列表分为左右两个列表,分别对应左子树的中序列表和右子树的中序列表
         // [ [左子树中序遍历结果]   头结点   [右子树中序遍历结果] ]
         int loc = umap[preorder[pstart]];
         // 左子树的中序列表的长度
         int left_len = loc - istart;
 ​
         // 递归创建左子树,前序的[ pstart + 1....pstart + left_len] 对应中序的 [istart... loc - 1]
         cur->left = createTree(preorder,pstart + 1, pstart + left_len, inorder,istart,loc-1);
         // 递归创建右子树,前序的[ pstart + left_len + 1 ... pend ] 对应中序的 [loc + 1 ... iend]
         cur->right = createTree(preorder,pstart + left_len + 1,pend, inorder,loc + 1,iend);
         return cur;
     }
 ​
     TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
         int len = preorder.size() - 1;
         
         for(int i=0;i<=len;i++)
         {
             umap[inorder[i]] = i;
         }
 ​
         return createTree(preorder,0,len, inorder,0,len);
     }
 };

复杂度分析

时间复杂度O(N),一共有 N个节点,hash 占用 O(N),递归占用O(N)

空间复杂度O(N)hash 占用 O(N),递归栈的开销占用 O(N)

后续遍历和中序遍历构建二叉树参考下面的题目

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

 // https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/description/
 // 106. 从中序与后序遍历序列构造二叉树
 ​
 #include<iostream>
 #include<vector>
 #include<unordered_map>
 using namespace std;
 ​
 struct TreeNode {
     int val;
     TreeNode *left;
     TreeNode *right;
     TreeNode() : val(0), left(nullptr), right(nullptr) {}
     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 };
 class Solution {
 private:
     // 使用hash表构建中序排列遍历中元素的位置
     unordered_map<int,int> umap;
 public:    
     TreeNode* createTree(vector<int>& postorder,int pstart ,int pend,vector<int>& inorder,int istart,int iend)
     {
         if(istart > iend)
         {
             return nullptr;
         }
 ​
         // 构建当前节点
         TreeNode *cur = new TreeNode(postorder[pend]);
         
         // 找到头结点在中序中的位置后,将中序列表分为左右两个列表,分别对应左子树的中序列表和右子树的中序列表
         // [ [左子树中序遍历结果]   头结点   [右子树中序遍历结果] ]
         int loc = umap[postorder[pend]];
         // 左子树的中序列表的长度
         int left_len = loc - istart;
 ​
         // 递归创建左子树,后序的[ pstart....pstart + left_len - 1] 对应中序的 [istart... loc - 1]
         cur->left = createTree(postorder,pstart, pstart + left_len - 1, inorder,istart,loc-1);
         // 递归创建右子树,后序的[ pstart + left_len ... pend - 1 ] 对应中序的 [loc + 1 ... iend]
         cur->right = createTree(postorder,pstart + left_len,pend - 1, inorder,loc + 1,iend);
         return cur;
     }
 ​
     TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
         int len = inorder.size() - 1;
         
         for(int i=0;i<=len;i++)
         {
             umap[inorder[i]] = i;
         }
 ​
         return createTree(postorder,0,len, inorder,0,len);
     }
 };

复杂度分析

时间复杂度O(N),一共有 N个节点,hash 占用 O(N),递归占用O(N)

空间复杂度O(N)hash 占用 O(N),递归栈的开销占用 O(N)

更多相关知识:github.com/pingguo1987…