要求:
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
示例:
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回
3
/ \
9 20
/ \
15 7
思路:
使用递推:
- 前序数组=[根,左子树,右子树], 中序数组=[左子树,根,右子树]
- 参数:pre_root(根节点在前序遍历数组中的索引), in_left(左边界索引),in_right(右边界索引)
- 终止条件:in_left > in_right
- 返回值:root
- 递推工作:
- 找根节点root。先序遍历的第一个元素就是根节点,pre_root
- 搜索root在中序遍历数组中的索引,这样依据根节点就可以分割开左右子树。可以用HashMap遍历中序数组,进行存储,这样通过键值对查找的速度更快。
- 构建root的左右子树:recur
- 边界值的更新:左子树:pre_root+1, 左边界 in_left, 右边界 i-1。右子树:i-in_left+pre_root+1(根节点+左子树长度+1),左边界 i+1, 右边界 in_right.
- recur中: 1. 先判断左右边界关系,看是否要跳出循环 2. 更新根节点,根节点始终来源于preorder中 3. 去inorder中获取根节点的索引i 4. 更新左子树 (pre_root+1, in_left, i-1) 5. 更新右子树 (pre_root+1+i-in_left, i+1, in_right) 6. 返回root 7. 以上的索引分别在(先序,中序,中序)数组中。
代码
class solution {
HashMap<Integer, Integer> dic = new HashMap<>();
int[] po;//新建一个数组来拷贝先序数组中的元素,这样就不会改变先序数组中原始元素的位置了
public TreeNode buildTree(int[] preorder, int[] inorder) {
po = preorder;
for (int i = 0; i < inorder.length; i++) {
dic.put(inorder[i], i);
}
return recur(0, 0, inorder.length-1);//0是先序数组中的第0个元素后两个是中序遍历的元素索引边界
}
public TreeNode recur(int pre_root, int in_left, int in_right) {
if (in_left > in_right) return null;//跳出边界的条件
TreeNode root = new TreeNode(po[pre_root]);//获取根节点
int i = dic.get(po[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;
}
}