题目27:105. 从前序与中序遍历序列构造二叉树
同类题目
前置知识
- 无
题目描述
给定两个整数数组 preorder 和 inorder ,其中 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 <= 3000inorder.length == preorder.length-3000 <= preorder[i], inorder[i] <= 3000preorder和inorder均 无重复 元素inorder均出现在preorderpreorder保证 为二叉树的前序遍历序列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)。
后续遍历和中序遍历构建二叉树参考下面的题目
// 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…