LeetCode-105-从前序与中序遍历序列构造二叉树
105. 从前序与中序遍历序列构造二叉树
难度中等
根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
解法、递归 分治
先序遍历的顺序是根节点,左子树,右子树。中序遍历的顺序是左子树,根节点,右子树。
所以我们只需要根据先序遍历得到根节点,然后在中序遍历中找到根节点的位置,它的左边就是左子树的节点,右边就是右子树的节点。
生成左子树和右子树就可以递归的进行了。
preorder = [3,9,20,15,7]
inorder = [9,3,15,20,7]
首先根据 preorder 找到根节点是 3
然后根据根节点将 inorder 分成左子树和右子树
左子树
inorder [9]
右子树
inorder [15,20,7]
把相应的前序遍历的数组也加进来
左子树
preorder[9]
inorder [9]
右子树
preorder[20 15 7]
inorder [15,20,7]
现在我们只需要构造左子树和右子树即可,成功把大问题化成了小问题
然后重复上边的步骤继续划分,直到 preorder 和 inorder 都为空,返回 null 即可
事实上,我们不需要真的把 preorder 和 inorder 切分了,只需要用分别用两个指针指向开头和结束位置即可。注意下边的两个指针指向的数组范围是包括左边界,不包括右边界。
class Solution {
public static TreeNode buildTree(int[] preorder, int[] inorder) {
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < inorder.length; i++) {
map.put(inorder[i], i);
}
return f(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1, map);
}
public static TreeNode f(int[] pre, int L1, int R1, int[] in, int L2, int R2, HashMap<Integer, Integer> map) {
if (L1 > R1) {
return null;
}
TreeNode head = new TreeNode(pre[L1]);
if (L1 == R1) {
return head;
}
int findIndex = map.get(pre[L1]);
head.left = f(pre, L1 + 1, L1 + findIndex - L2, in, L2, findIndex - 1, map);
head.right = f(pre, L1 + findIndex - L2 + 1, R1, in, findIndex + 1, R2, map);
return head;
}
}