1. 题目描述
2. 题目理解
前序遍历数组的首元素一定是当前子树的根节点。根据这一性质,找到当前子树的根节点,然后查找该节点在中序遍历数组中的位置,可以得到当前根节点左子树中元素的个数。将中序遍历按照根节点分为左右两部分,对应左右子树的中序遍历;同时将前序遍历按照根节点以及根节点左子树中元素的个数,也分成左右两部分,对应左右子树的前序遍历。
按照以上思路,用递归的方式可以构造出整个树。
3. 代码
3.1 C语言代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
//递归函数:通过递归,构造二叉树
void bulid(struct TreeNode* head, int* preorder, int preorderSize, int* inorder, int inorderSize);
//找到值为val的元素在当前中序遍历数组中的位置
int findIndex(int val, int* inorder, int inorderSize);
//主函数,提供通用外部接口
struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int inorderSize){
if(preorderSize==0)return NULL;//传入参数为空,返回NULL
struct TreeNode* head=(struct TreeNode*)malloc(sizeof(struct TreeNode));
bulid(head,preorder,preorderSize,inorder,inorderSize);
return head;
}
//递归函数:通过递归,构造二叉树
void bulid(struct TreeNode* head, int* preorder, int preorderSize, int* inorder, int inorderSize){
if(preorderSize==0)return;
//初始化根节点
head->val=preorder[0];
head->left=NULL;
head->right=NULL;
int idx=findIndex(preorder[0],inorder,inorderSize);//找到根节点在中序遍历中的位置
if(idx!=0){//存在左子树
//构造左子树的节点,并初始化
struct TreeNode* leftRoot=(struct TreeNode*)malloc(sizeof(struct TreeNode));
leftRoot->val=preorder[1];
leftRoot->right=NULL;
leftRoot->left=NULL;
head->left=leftRoot;//构造左子树的连接
//更新左子树的前序和中序遍历数组以及数组长度
//前序遍历数组从preorder[1]开始,到preorder[idx-1],总共idx个元素
//中序遍历数组从inorder开始,大小与前序遍历数组相等
int* newPreorder=&preorder[1];
int newPreorderSize=idx;
int* newInorder=inorder;
int newInorderSize=newPreorderSize;
//递归调用,构造左子树
bulid(leftRoot,newPreorder,newPreorderSize,newInorder,newInorderSize);
}
if(idx<inorderSize-1){//存在右子树
//构造右子树的节点,并初始化
struct TreeNode* rightRoot=(struct TreeNode*)malloc(sizeof(struct TreeNode));
rightRoot->val=preorder[idx+1];
rightRoot->left=NULL;
rightRoot->right=NULL;
head->right=rightRoot;//构造右子树的连接
//更新右子树的前序和中序遍历数组,
///前序遍历数组从idx+1开始,数组大小=preorderSize-(idx+1),中序遍历数组相同
int* newPreorder=&preorder[idx+1];
int newPreorderSize=preorderSize-idx-1;
int* newInorder=&inorder[idx+1];
int newInorderSize=newPreorderSize;
//递归调用,构造右子树
bulid(rightRoot,newPreorder,newPreorderSize,newInorder,newInorderSize);
}
return;
}
//找到值为val的元素在当前中序遍历数组中的位置
int findIndex(int val, int* inorder, int inorderSize){
int i=0;
for(;i<inorderSize;i++){
if(inorder[i]==val)return i;
}
return -1;
}
3.2 C++代码
C++的代码主要用了个哈希表,简化了查找的过程。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
unordered_map<int, int> index;
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int n=preorder.size();
if(n==0)return NULL;//传入参数为空,返回NULL
for(int i=0;i<n;i++){//构造哈希表,帮助快速定位根节点
index[inorder[i]]=i;
}
TreeNode* head = new TreeNode(preorder[0]);
bulid(head,preorder,inorder,0,n-1,0,n-1);
return head;
}
//递归函数:通过递归,构造二叉树
void bulid(struct TreeNode* head, vector<int>& preorder, vector<int>& inorder,
int preorderLeft,int preorderRight,int inorderLeft,int inorderRight){
if(!(preorderLeft^preorderRight))return;
int idx=index[preorder[preorderLeft]];//找到根节点在中序遍历中的位置
//printf("%d",idx);
if(idx>inorderLeft){//存在左子树
//构造左子树的节点,并初始化
TreeNode* leftRoot=new TreeNode(preorder[preorderLeft+1]);
head->left=leftRoot;//构造左子树的连接
//更新左子树的前序和中序遍历数组的范围
//idx - inorderLeft记录了当前树中根节点左侧的元素的个数(也就是左子树中元素的个数,也就是前序遍历数组的大小)
//因此前序遍历数组的区间为[preorderLeft+1,preorderLeft + idx - inorderLeft]
//中序遍历数组按照idx分开,取左边的部分即可
int newPreorderLeft=preorderLeft+1;
int newPreorderRight= preorderLeft + idx - inorderLeft;//这个实际是preorderLeft+1+idx-inorderLeft-1
int newInorderLeft=inorderLeft;
int newInorderRight=idx-1;
//递归调用,构造左子树
bulid(leftRoot,preorder,inorder,newPreorderLeft,newPreorderRight,newInorderLeft,newInorderRight);
}
if(idx<inorderRight){//存在右子树
//构造右子树的节点,并初始化
struct TreeNode* rightRoot=new TreeNode(preorder[preorderLeft+idx-inorderLeft+1]);
head->right=rightRoot;//构造右子树的连接
//更新右子树的前序和中序遍历数组的范围
//前序遍历中,右子树的前序遍历数组紧跟在左子树的前序遍历数组后面,因此newPreorderLeft实际等于newPreorderRight+1
//中序遍历数组按照idx分开,右边部分属于右子树的中序遍历
int newPreorderLeft=preorderLeft+idx-inorderLeft+1;
int newPreorderRight=preorderRight;
int newInorderLeft=idx+1;
int newInorderRight=inorderRight;
//递归调用,构造右子树
bulid(rightRoot,preorder,inorder,newPreorderLeft,newPreorderRight,newInorderLeft,newInorderRight);
}
return;
}
};