目录
重建二叉树
描述
输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
示例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]
限制
0 <= 节点个数 <= 5000
数据结构
public class TreeNode {
public int val = 0;
public TreeNode left = null;
public TreeNode right = null;
public TreeNode(int val){
this.val=val;
}
}
方法一:递归
首先我们根据先序遍历下标0的元素为根节点这个特点,将中序遍历可以分为左子树的元素和右子树的元素,然后反过来将先序遍历分为左右子树,这样不断地重建子树,利用递归求解。
class Solution {
private Map<Integer,Integer> indexMap;
public TreeNode buildTree(int[] preorder, int[] inorder) {
int n=inorder.length;
indexMap=new HashMap<>();
for (int i = 0; i < n; i++) {
indexMap.put(inorder[i],i);
}
return rebuildTree(preorder,inorder,0,n-1,0,n-1);
}
public TreeNode rebuildTree(int[] preorder, int[] inorder, int preorder_left,int preorder_right,int inorder_left,int inorder_right){
if (preorder_left>preorder_right){
return null;
}
int rootIndex=indexMap.get(preorder[preorder_left]);//根节点在中序遍历中的下标
TreeNode root=new TreeNode(preorder[preorder_left]);//构造根节点
int leftsize=rootIndex-inorder_left;//左子树的元素个数
root.left=rebuildTree(preorder,inorder,preorder_left+1,preorder_left+leftsize,inorder_left,rootIndex-1);//递归构造左子树
root.right=rebuildTree(preorder,inorder,preorder_left+leftsize+1,preorder_right,rootIndex+1,inorder_right);//递归构造右子树
return root;
}
}
方法二:迭代(待补充)
迭代使用的思想比较巧妙,也就是比较难想。
对于前序遍历中任意两个连续节点u和v,根据前序遍历的特点,u和v只存在两种关系:
- v是u的左儿子:这是因为在遍历到根节点u之后,下一个遍历就是其左儿子,即v节点。
- u没有左儿子:如果u没有左儿子,那么v就是u或者u的某个祖先节点的右儿子。因为u没有左儿子,那么前序遍历会接着访问右儿子,如果右儿子也没有那么就向上回溯访问第一个有右儿子的节点。