题目描述
https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
思路
首先我们在上一篇文章中解释了前序遍历和中序遍历的含义,因为是树的结构,一般都是用递归来实现。
- 用数学归纳法的思想就是,假设最后一步,就是root的左右子树都已经重建好了,那么我只要考虑将root的左右子树安上去即可。
- 根据前序遍历的性质,第一个元素必然就是root,那么下面的工作就是如何确定root的左右子树的范围。
- 根据中序遍历的性质,root元素前面都是root的左子树,后面都是root的右子树。那么我们只要找到中序遍历中root的位置,就可以确定好左右子树的范围。
简单来说就是当前前序遍历的结果,第一个元素必然是当前节点的值,而对于中序遍历来说,当前节点值的位置的前面都是左子树的值,后面都是右子树的值,所以根据这个思想,重新构建二叉树。
实现代码
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode build(int[] pre,int[] ino){
if(ino.length == 0 || pre.length == 0)
return null;
int i = 0,target = pre[0];//target 是前序遍历的第一个元素,即当前节点的值
for(;i < ino.length;i++){
if(ino[i] == target) //在中序遍历的数组中找到当前节点的位置,这样就可以区分当前节点的左子树和右子树
break;
}
TreeNode node = new TreeNode(ino[i]); // ino[i]是当前节点
node.left = build(Arrays.copyOfRange(pre,1,i+1),Arrays.copyOfRange(ino,0,i));
//Arrays.copyOfRange(),是一个左闭右开的,当前节点的左子树的长度为i,所以将当前节点的左子树的前序遍历数组和中序遍历数组传入。
node.right = build(Arrays.copyOfRange(pre,i+1,pre.length),Arrays.copyOfRange(ino,i+1,ino.length));
return node;
}
public TreeNode buildTree(int[] preorder, int[] inorder) {
return build(preorder,inorder);
}
}