文章目录
1. 从前序与中序遍历序列构造二叉树 (中序与后序同理)
方法1:利用根结点位置不断递归分割出数组中的左子树和右子树
public class Solution {
public TreeNode BuildTree(int[] preorder, int[] inorder) {
TreeNode root=new TreeNode();
if(preorder.Length==0)
return root=null;
// 二叉树不为空 直到根结点在前序遍历以及后序遍历中的位置,然后找到根结点在中序遍历中的位置
root.val=preorder[0];
// 如果数组长度为1,递归传入的数组值就是根结点的值,然后直接返回,代码不需要往下进行(小优化)
if(preorder.Length==1)
return root;
// 找到根结点在中序遍历中的位置 这样就可以分出数组中的左子树结点和右子树结点
int k=0;
for(int i=0;i<inorder.Length;i++)
{
if(root.val==inorder[i])
{
k=i;
break;
}
}
// 根的左子树由k个结点组成,特征为:前序序列--preorder[1],...,preorder[k] 中序序列--inorder[0],...inorder[k-1]
// 根的右子树由初始序列长度(preorder.Length)-1-k个结点组成,特征为:
// 前序序列--preorder[k+1],...,preorder[preorder.Length-1] 中序序列--inorder[k+1],...,inorder[inorder.Length-1]
// 定义数组,存储对应遍历序列中对应索引左右子树结点值
int[] preLeftTree=new int[k];
int[] inLeftTree=new int[k];// 根据前中遍历序列可知左子树由k个结点组成
int[] preRightTree=new int[preorder.Length-1-k];
int[] inRightTree=new int[preorder.Length-1-k];// 右子树同理
if(preorder.Length>0)
{
// 向左子树数组中添加对应元素(从0索引处添加) 这里使用for循环为了给定义的初始数组赋值,随便用几个for循环都可以
for(int i=0;i<k;i++)
{
preLeftTree[i]=preorder[i+1];// 前序序列中对应的左子树结点存储数组中
inLeftTree[i]=inorder[i];// 中序序列中对应的左子树结点存储数组中
}
// 左子树递归
root.left=BuildTree(preLeftTree,inLeftTree);
// 向右子树数组中添加对应元素
int index=0;// 索引为0,从数组初始位置开始存储结点的值
for(int i=k+1;i<preorder.Length;i++)
{
preRightTree[index]=preorder[i];// 同理
inRightTree[index]=inorder[i];
index++;
}
// 右子树递归
root.right=BuildTree(preRightTree,inRightTree);
}
return root;
}
}
前序和后序遍历序列不能构造二叉树,因为根结点在两个序列的两端,并不能根据根结点的位置分割数组,也就是不能找出根结点root的左子树和右子树,所以不能唯一确定一颗二叉树。
方法2:利用左右子树在vector中对应的区间构建二叉树,避免方法1每次递归创建数组带来时间与空间上的消耗,同时使用hashmap,避免循环在中序序列中查找根节点下标带来时间上的消耗
/**
* Definition for a binary tree node.
* 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 {
public:
// 遍历序列中均无重复元素
unordered_map<int,int> hash;
// 确定递归的参数和返回值
TreeNode* build(vector<int>& preorder,int preorderBegin,int preorderEnd,vector<int>& inorder,int inorderBegin,int inorderEnd)
{
// 如果左右子树的遍历序列为空,返回nullptr
if(preorderBegin>preorderEnd)
return nullptr;
// 找到根节点所在位置索引
int k=hash[preorder[preorderBegin]];
TreeNode* root=new TreeNode(preorder[preorderBegin]);// 根节点
int leftSize=k-inorderBegin;
// 左子树节点个数 k-0 右子树节点个数inorder.size()-k-1
// 前序与中序 左子树所在区间
root->left=build(preorder,preorderBegin+1,preorderBegin+leftSize,inorder,inorderBegin,k-1);
// 前序与中序 右子树所在区间
root->right=build(preorder,preorderBegin+leftSize+1,preorderEnd,inorder,k+1,inorderEnd);
return root;
}
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
// 避免使用循环在中序遍历序列中找到根节点所在的位置,这里使用unorder_map存储inorder中的所有元素,key为元素值,value为索引
for(int i=0;i<inorder.size();++i)
{
hash[inorder[i]]=i;//key为结点值 value为索引
}
// 这里传入不同遍历序列的左子树、右子树所在区间***索引***
return build(preorder,0,preorder.size()-1,inorder,0,inorder.size()-1);
}
};
2. 从中序与后序遍历序列构造二叉树
/**
* Definition for a binary tree node.
* 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 {
public:
unordered_map<int,int> hash;// 因为遍历序列都由不同的值组成,所以不用使用maltimap
// 确定递归参数和返回值
TreeNode* myBuild(vector<int>& inorder,int inorderBegin,int inorderEnd,vector<int>& postorder,int postorderBegin,int postorderEnd)
{
// 递归终止条件
if(inorderBegin>inorderEnd)
return nullptr;
int k=hash[postorder[postorderEnd]];// 中序根节点所在索引,该索引可以将其分为左右子树
TreeNode* root=new TreeNode(postorder[postorderEnd]);// 创建根节点
// 左子树数量
int leftSize=k-inorderBegin;
// 确定递归的单层逻辑
// 填入中序序列左子树在vector中索引(前闭后闭) 后序也是左子树的索引
root->left=myBuild(inorder,inorderBegin,k-1,postorder,postorderBegin,postorderBegin+leftSize-1);
// 同理
root->right=myBuild(inorder,k+1,inorderEnd,postorder,postorderBegin+leftSize,postorderEnd-1);
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
// 向哈希表填入数据
for(int i=0;i<inorder.size();++i)
{
hash[inorder[i]]=i;// key为节点值,value为节点下标索引
}
return myBuild(inorder,0,inorder.size()-1,postorder,0,postorder.size()-1);
}
};
3. 最大二叉树
/**
* Definition for a binary tree node.
* 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 {
public:
// 确定递归参数和返回值 与根据前序中序序列构建二叉树类似
TreeNode* myBuild(vector<int>& nums,int begin,int end)
{
if(begin>end)
return nullptr;
// 找到数组中根节点的索引
int k=begin; // 初始化 k为nums中最大值下标
int maxValue=nums[begin];// 找到最大值
// 时间复杂度O(n)
for(int i=begin;i<=end;++i)
{
if(nums[i]>maxValue)
{
k=i;
maxValue=nums[i];
}
}
TreeNode* root=new TreeNode(nums[k]);
root->left=myBuild(nums,begin,k-1);
root->right=myBuild(nums,k+1,end);
return root;
}
TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
return myBuild(nums,0,nums.size()-1);
}
};