lettcode题目地址
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
思路:
前序遍历的数组按照 【根节点 | 左子树 | 右子树】排列
中序遍历的数组按照 【左子树 | 根节点 | 右子树】排列
因为数组中的节点值不重复,所以我们可以根据前序遍历的首节点值,来确定在中序遍历序列中的根节点值位置。
然后确定当前节点的值即为该根节点。然后分别递归中序遍历序列中的左子树和中序遍历序列中的右子树。
递归函数的参数:前序遍历序列中当前根节点的下标k,中序遍历序列的左边界left,中序遍历序列的右边界right。
递归的出口:如果左边界left > 右边界right,则表示当前无子树,可以直接返回
递归函数的工作:设置前序遍历序列中下标k所在的数为当前子树的根节点。然后遍历一下中序遍历序列left - right 的区间,找到中序遍历序列中的根节点下标index,再次递归左子树 【k + 1,left,index - 1】和右子树【k + (index - left) +1,index + 1,right】
返回值:每个函数返回自己这颗子树的根节点。
class Solution {
HashMap<Integer, Integer> dic = new HashMap<>();// 使用 hashmap 做中序遍历的值-下标映射,可以提高我们查找根节点在中序遍历序列中的下标。因为我们已经从前序遍历中获取了根节点的值。
int[] pre;
public TreeNode buildTree(int[] preorder, int[] inorder) {
pre = preorder;
for(int i = 0; i < inorder.length; i++)
dic.put(inorder[i], i); // 以中序遍历的值为键,以其下标为值
return recur(0, 0, inorder.length - 1);// 第一个0表示,此时可以确定的根节点是前序遍历为0的位置。后面两个数表示的是该子树的左右边界。
}
TreeNode recur(int pre_root, int in_left, int in_right) {
if(in_left > in_right) return null;// 当前子树的左区间大于右区间,所以这不是一棵子树,可以直接 return
TreeNode root = new TreeNode(pro[pre_root]);// 设置当前这棵子树的根节点
int i = dic.get(pro[pre_root]);// 获取当前子树根节点在中序遍历中的下标,然后再划分出左右子树,依次递归
root.left = recur(pre_root + 1, in_left, i - 1);
root.right = recur(pre_root + i - in_left + 1, i + 1, in_right);// 前序遍历的规律 【根节点 | 左子树 | 右子树】,所以当前子树的右子树的根节点在前序遍历序列中的下标为:当前根节点加上左子树结点的个数
return root;
}
}