import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 *   public TreeNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

/**
 * NC12 重建二叉树
 * @author d3y1
 */
public class Solution {
    HashMap<Integer,Integer> inMap = new HashMap<>();

    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 相似 -> NC223 从中序与后序遍历序列构造二叉树 [nowcoder]
     *
     * @param preOrder int整型一维数组
     * @param vinOrder int整型一维数组
     * @return TreeNode类
     */
    public TreeNode reConstructBinaryTree (int[] preOrder, int[] vinOrder) {
        // return solution1(preOrder, vinOrder);
        // return solution2(preOrder, vinOrder);
        return solution3(preOrder, vinOrder);
    }

    /**
     * 递归
     * @param preOrder
     * @param vinOrder
     * @return
     */
    private TreeNode solution1(int[] preOrder, int[] vinOrder){
        return construct(preOrder, vinOrder);
    }

    /**
     * 递归
     * @param preOrder
     * @param vinOrder
     * @return
     */
    public TreeNode construct (int[] preOrder, int[] vinOrder) {
        int n = preOrder.length;
        if(n == 0){
            return null;
        }
        // 当前根结点
        int rootVal = preOrder[0];
        TreeNode root = new TreeNode(rootVal);
        // 当前根结点 左子树节点个数
        int left = 0;
        while(vinOrder[left] != rootVal){
            left++;
        }
        if(left > 0){
            // int[] pre = new int[left];
            // int[] vin = new int[left];
            // System.arraycopy(preOrder, 1, pre, 0, left);
            // System.arraycopy(vinOrder, 0, vin, 0, left);
            // root.left = construct(pre, vin);

            root.left = construct(Arrays.copyOfRange(preOrder, 1, left+1), Arrays.copyOfRange(vinOrder, 0, left));
        }
        // 当前根结点 右子树节点个数
        int right = n-(left+1);
        if(right > 0){
            // int[] pre = new int[right];
            // int[] vin = new int[right];
            // System.arraycopy(preOrder, left+1, pre, 0, right);
            // System.arraycopy(vinOrder, left+1, vin, 0, right);
            // root.right = construct(pre, vin);

            root.right = construct(Arrays.copyOfRange(preOrder, left+1, n), Arrays.copyOfRange(vinOrder, left+1, n));
        }

        return root;
    }

    //////////////////////////////////////////////////////////////////////////////////////

    /**
     * 哈希 + 递归
     * @param preOrder
     * @param vinOrder
     * @return
     */
    private TreeNode solution2(int[] preOrder, int[] vinOrder){
        int n = vinOrder.length;
        if(n == 0){
            return null;
        }

        // 哈希: val -> idx
        for(int i=0; i<n; i++){
            inMap.put(vinOrder[i], i);
        }

        // 根结点
        TreeNode root = new TreeNode(preOrder[0]);
        // 递归遍历
        dfs(preOrder, root, 0, n-1, 0, n-1);

        return root;
    }

    /**
     * 递归遍历
     * @param preOrder
     * @param root
     * @param inLeft
     * @param inRight
     * @param preLeft
     * @param preRight
     */
    private void dfs(int[] preOrder, TreeNode root, int inLeft, int inRight, int preLeft, int preRight){
        int inRootIdx = inMap.get(root.val);

        int leftSize = inRootIdx-inLeft;
        int rightSize = inRight-inRootIdx;

        // 有左子树
        if(leftSize > 0){
            root.left = new TreeNode(preOrder[preLeft+1]);
            dfs(preOrder, root.left, inLeft, inRootIdx-1, preLeft+1, preLeft+leftSize);
        }

        // 有右子树
        if(rightSize > 0){
            root.right = new TreeNode(preOrder[preLeft+leftSize+1]);
            dfs(preOrder, root.right, inRootIdx+1, inRight, preLeft+leftSize+1, preRight);
        }
    }

    //////////////////////////////////////////////////////////////////////////////////////

    // 前序遍历根结点索引
    private int preRootIdx;

    /**
     * 哈希 + 递归
     * @param preOrder
     * @param vinOrder
     * @return
     */
    private TreeNode solution3(int[] preOrder, int[] vinOrder){
        int n = preOrder.length;
        preRootIdx = 0;

        // 哈希: val -> idx
        for(int i=0; i<n; i++){
            inMap.put(vinOrder[i], i);
        }

        return build(preOrder, 0, n-1);
    }

    /**
     * 递归遍历
     *
     * 二叉树前序遍历: 根 -> 左 -> 右
     * 可利用该性质直接找到前序遍历根节点, 子树遍历先左后右: 左 -> 右
     *
     * @param preOrder
     * @param inLeft
     * @param inRight
     * @return
     */
    private TreeNode build(int[] preOrder, int inLeft, int inRight){
        if(inLeft > inRight){
            return null;
        }

        // 根
        int preRootVal = preOrder[preRootIdx++];
        TreeNode root = new TreeNode(preRootVal);

        if(inLeft == inRight){
            return root;
        }

        // 中序遍历根结点索引
        int inRootIdx = inMap.get(preRootVal);

        // 左
        root.left = build(preOrder, inLeft, inRootIdx-1);
        // 右
        root.right = build(preOrder, inRootIdx+1, inRight);


        return root;
    }
}