题目描述
给定一棵树的前序遍历 preorder 与中序遍历 inorder。请构造二叉树并返回其根节点。
示例1:
Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]Output: [3,9,20,null,null,15,7]
示例2:
Input: preorder = [-1], inorder = [-1]Output: [-1]
思路
分治思想,递归构造树。
对于中序遍历:对于某个结点,在中序遍历中的位置假设是3,那么位置0~2都是在该结点的左子树上,4~结尾都是在该结点的右子树上。
对于前序遍历:第一个结点就是跟结点。
举个例子:
preorder = [3,9,20,15,7]inorder = [9,3,15,20,7]
首先,preorder的第一个结点是3,那么该结点就是整个树的根节点。然后,去找3在中序遍历中的位置,发现下标为1,那么下标为0的都在3的左子树上,下标大于1的都在右子树上。即, 左子树:
preorder = [9]inorder = [9]
右子树:
preorder = [20, 15, 7]inorder = [15, 20, 7]
左子树只有一个节点了,直接连接。
那么右子树,又按照同样的方式构造,取preorder的第一个元素,去inorder中找下标。
小技巧:
- 在inorder中能知道左边有多少个结点,那么对应的,去preorder中找相同数量的结点即可。
- 真正做这段道题时,需要用到多个下标,和下标的转换关系,建议记好思路以后画一个图来保证下标转化正确。
- 两个数组都是左闭右开,记住就好。
- 用map来保存inorder的下标,减少时间复杂度。
class Solution {Map<Integer, Integer> map;public TreeNode buildTree(int[] preorder, int[] inorder) {// map保存下标map = new HashMap<>();for (int i = 0; i < inorder.length; i++) {map.put(inorder[i], i);}// 参数为两个数组和两组下标。// 左闭右开,所以传lengthTreeNode node = helpder(preorder, 0, preorder.length, inorder, 0, inorder.length);return node;}private TreeNode helpder(int[] preorder, int p_start, int p_end, int[] inorder, int i_start, int i_end) {if (p_start == p_end) {return null;}int val = preorder[p_start];TreeNode root = new TreeNode(val);int root_idx = map.get(val);int left_num = root_idx - i_start;// 同样的,右边是开的,所以是p_start + left_sum + 1和root_idx;// 以及p_end和i_endroot.left = helpder(preorder, p_start + 1, p_start + left_num +1, inorder, i_start, root_idx);root.right = helpder(preorder, p_start + left_num + 1, p_end, inorder, root_idx + 1, i_end);return root;}}
