剑指offer07. 重建二叉树

145 阅读2分钟

要求:

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

示例:

前序遍历 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
  • 递推工作:
  1. 找根节点root。先序遍历的第一个元素就是根节点,pre_root
  2. 搜索root在中序遍历数组中的索引,这样依据根节点就可以分割开左右子树。可以用HashMap遍历中序数组,进行存储,这样通过键值对查找的速度更快。
  3. 构建root的左右子树:recur
  4. 边界值的更新:左子树:pre_root+1, 左边界 in_left, 右边界 i-1。右子树:i-in_left+pre_root+1(根节点+左子树长度+1),左边界 i+1, 右边界 in_right.
  5. 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;
    }
}