本质上就是前序遍历的框架。
前序数组的第一个是根节点,找到中序数组它的索引 (可用map降低时间复杂度),中序数组以它为中心,左边是左子树,右边是右子树。
将大问题化成小问题,利用递归。 而指针可以在每轮递归中作为通信的工具。
上一层递归告诉下一层“你该缩小范围找了”。
left每一层递归返回给上一层的是刚刚遍历完的根节点的下一个,而right返回的是刚刚遍历完的(根节点当前位置 + 左子树的节点个数)的下一个。这跟前序数组的前序遍历性质有关,而我们又是基于前序数组来重构二叉树的。

class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        //用map来缓存值和对应的索引,方便在递归方法中查找,降低时间复杂度
        HashMap<Integer, Integer> map = new HashMap<>();
        for(int i = 0; i < inorder.length; i++){
            map.put(inorder[i] , i);
        }
        return builTree(preorder, 0, preorder.length, inorder, 0, inorder.length, map);

    }
    private TreeNode builTree(int[] preorder, int p_start, int p_end, int[] inorder, int i_start, int i_end, HashMap<Integer, Integer> map){
        //递归出口 当指针相等时,左右子树已经找完了
        if(p_start == p_end)
            return null;

        int root_val = preorder[p_start];
        //构建节点
        TreeNode root = new TreeNode(root_val);
        //找到索引,利用这个位置将数组分成2部分, 前序数组的左部分就是左子树 
        int i_root_index = map.get(root_val);
        int leftNum = i_root_index - i_start;

        //前序遍历 注意左右子树的索引 start和end区间就是一个子树
        root.left = builTree(preorder, p_start + 1, p_start + leftNum + 1, inorder, i_start, i_root_index, map);
        root.right = builTree(preorder, p_start + leftNum + 1, p_end, inorder, i_root_index + 1, i_end, map);
        return root;
    }
}