输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题目难度中等。
首先需要二叉树的基本基本知识,前序、中序、后序 三种遍历顺序
即使掌握了三种遍历顺序,第一次拿到题,还是感觉一头雾水,没法下手。
需要仔细观察前序和中序的规律
很明显可以看出根节点在两个序列中的位置。
但仅仅凭借这个信息还是很难重构出二叉树的。
还需要注意二叉树的两个特点:
1:中序遍历访问顺序:左子树的所有内容->跟节点->右子树
2:前序遍历的访问顺序:根节点->左子树->右子树
我们可以推断得到下图的规律,那么还是会有疑问,即使我知道了根节点以及左右子树的节点,那有怎么重建二叉树呢?
3 9 20 15 7
根节点 左子树 右子树
9 3 15 20 7
左子树 根节点 右子树
我们先简化问题,如果二叉树是一个最简单的二叉树,只有一个根节点,一个左子树,一个右子树,那么,我们是不是就可以根据
前文总结的两个特点完成重建了。
到这里,有经验的同学就很容易想到递归了,一开始学习递归感觉很复杂,想不明白,但是,其实你只需要想清楚一个最小的处理单元的逻辑结构就够了。
剩下的细节问题还是看代码吧
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
struct TreeNode* buildTreeCore(int *startPreorder,int *endPreorder,
int *startInorder, int *endInorder){
int root_value = *startPreorder;
struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode));
root->val = root_value;
root->left = root->right = NULL;
if(startPreorder == endPreorder && startInorder == endInorder
&& *startInorder == *endInorder)
return root;
//find pos at inorder
int *root_node = startInorder;
while(*root_node != root_value){
root_node++;
}
//cal left tree length and right tree length
int left_length = root_node - startInorder;
int *leftPreorder_end = startPreorder + left_length;
//make sure left and right tree haven
if(left_length >0)
root->left = buildTreeCore(startPreorder+1,leftPreorder_end,
startInorder,root_node-1);
if(root_node != endInorder)
root->right = buildTreeCore(leftPreorder_end+1,endPreorder,
root_node+1,endInorder);
return root;
}
struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int inorderSize){
if ( NULL == preorder || NULL == inorder || preorderSize <= 0
|| inorderSize <=0 || preorderSize!= inorderSize)
return NULL;
return buildTreeCore(preorder,preorder + preorderSize -1,
inorder, inorder + inorderSize - 1);
}
需要注意的是,写代码一定要严谨,该加上的判断一定要加上,特别是对于递归程序而言,如果终止条件不对,很容易陷入死循环,导致栈溢出