重建二叉树(中等)
2020年8月10日
题目来源:力扣
解题
前序遍历:DLR
中序遍历:LDR
这种题在选择题和填空题非常常见,一般会让你写出后序遍历,那他的规律就有:
前序遍历的第一个点一定是根节点。
如案例,前序遍历第一个点是3,那么根节点一定是3。
那么找3在中序遍历中的位置,并以它分割成左右子树
肉眼可以看到左子树只剩9一个节点了,但计算机不知道9是个叶子节点,得用叶子节点的定义告诉它
叶子节点没有子节点,那就是它的子节点都为空
计算机才能知道这是个叶子节点
看完3的左子树,来看3的右子树
有三个数值15,20,7,这时看前序遍历,哪个数字先出现,哪个就会是根节点,可以直观的看到是20
再在中序遍历中找20的左右子树,那就是15和7了
知道这个原理后,这道题就很好做了
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
//需要全局的前序遍历的数组
private int[] preorder;
//使用HashMap记录中序遍历,key为具体值,value为索引
private Map<Integer,Integer> inorder_map=new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
//前序遍历赋值到全局数组中
this.preorder=preorder;
int len=inorder.length;
for(int i=0;i<len;i++){
inorder_map.put(inorder[i],i);
}
//调用递归方法,把最大的子树范围传进去
return recur(0,0,len-1);
}
//构建递归方法,参数分别为前序遍历确立的根,子树的左边界,子树的右边界
private TreeNode recur(int root,int left_root,int right_root){
//如果左边界的值大于右边界,返回null
if(left_root>right_root)
return null;
//构建新的TreeNode
TreeNode node=new TreeNode(preorder[root]);
//根据前序遍历的数组取出根节点的值,按这个值查找在中序遍历数组的位置,以便于划分左右子树
int inorder_root_index=inorder_map.get(preorder[root]);
//取当前节点的左子树范围,调用递归。
//参数:前序遍历的下一个数,就会是下一个根节点;左边界不变,右边界为上个根节点的左一位
node.left=recur(root+1,left_root,inorder_root_index-1);
//取当前节点的右子树范围,调用递归
//参数:当前的根节点,加上左子树的数量,再加一就会是下一个根节点;左边界为上个根节点的后一位,右边界不变
//左子树的数量为:当前根节点在中序遍历的索引,减去中序遍历的左边界
node.right=recur(root+inorder_root_index-left_root+1,inorder_root_index+1,right_root);
return node;
}
}