105. Construct Binary Tree from Preorder and Inorder Traversal
https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/description/
106. Construct Binary Tree from Inorder and Postorder Traversal
https://leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/description/
889. Construct Binary Tree from Preorder and Postorder Traversal
https://leetcode.com/problems/construct-binary-tree-from-preorder-and-postorder-traversal
Note: 这三道题前提都是pre/inorder/post order 数组里的 num 都是distinct, 否则算法无法执行。
105/106: 这两题几乎一样,105 是给出preorder and inorder 求Tree, 106 是给出 postorder and inorder 求Tree ,共同点都是 具备inorder.
以105为例, preorder: root-->left-->right, 因此pre[0] 一定是root, 然后 后面的是 left and right,关键问题在于不知道从哪去划分left and right.
inorder: left-->root--->right, 因此只要找到root, 然后root 左边为 left, 右边为right, 关键问题是不知道root 的位置。
因此,结合preorder and inorder, 可以先通过pre[0] 确定 root 是谁,然后 在inorder 中找到root 位置,从而划分左右子树。
106 如果是 postorder, 那么 post[N-1] 为 root, 通过 inorder 找到root 位置再划分左右子树。
For example, given
preorder = [3,9,20,15,7] inorder = [9,3,15,20,7]
Return the following binary tree:
3 / \ 9 20 / \ 15 7
root pre[0] =3, inorder.indexOf(pre[0]=3) 确定 3的 index, 因此 left tree = [9] right tree=[15 20 7]
因此设计一个 dfs 函数:
dfs(int start_pre, int start_in, int end_in, int[] pre, int[] inorder)
注意 对于 preorder数组 ,只需要知道 start_pre 就够了,因为从start_pre 得到root信息。
class Solution { public TreeNode buildTree(int[] preorder, int[] inorder) { return helper(0, 0, inorder.length - 1, preorder, inorder); } public TreeNode helper(int preStart, int inStart, int inEnd, int[] preorder, int[] inorder) { if(preStart > preorder.length-1){ //仅仅处理 preorder = []的情况 return null; } TreeNode root = new TreeNode(preorder[preStart]); // find root index int index = inStart; for(; index<=inEnd && inorder[index] != root.val;) {index++;} //index-1 < inStart 说明左子树不存在,也可以在 递归出口时判断 root.left = index -1 <inStart ? null: helper(preStart+ 1, inStart, index-1, preorder, inorder); // index+1 > inEnd 说明右子树不存在,,也可以在 递归出口时判断 // preStart+ index-inStart +1 : preStart +1 + leftTree_len = preStart+1+ (index-1-inStart +1) root.right = index+1 > inEnd ? null: helper(preStart+ index-inStart +1, index+1, inEnd, preorder, inorder); return root; } }
这里唯一需要小心的是计算 root,right 时, preorder 的start index : preStart+ index-inStart +1
计算过程: left_tree start index = preStart+1, 然后 left tree 长度为: index- instart, 因此 right tree start index 为
preStart+ index-inStart +1
优化:上面算法每次需要一个for 循环寻找 root 在 inorder 里的index, 因此可以用一个map 去优化,避免用for 循环去查询。上面的算法只排名40% 左右, 而用map 优化后可以 排名97%。
class Solution { public TreeNode buildTree(int[] preorder, int[] inorder) { Map<Integer,Integer> map_in = new HashMap<>(); // val+index for(int i=0; i<inorder.length; i++){ map_in.put(inorder[i],i); } return helper(0, 0, inorder.length - 1, preorder, inorder,map_in); } public TreeNode helper(int preStart, int inStart, int inEnd, int[] preorder, int[] inorder,Map<Integer,Integer> map_in) { if(preStart > preorder.length-1){ //仅仅处理 preorder = []的情况 return null; } TreeNode root = new TreeNode(preorder[preStart]); // find root index int index = map_in.get(root.val); //for(; index<=inEnd && inorder[index] != root.val;) {index++;} //index-1 < inStart 说明左子树不存在,也可以在 递归出口时判断 root.left = index -1 <inStart ? null: helper(preStart+ 1, inStart, index-1, preorder, inorder,map_in); // index+1 > inEnd 说明右子树不存在,,也可以在 递归出口时判断 // preStart+ index-inStart +1 : preStart +1 + leftTree_len = preStart+1+ (index-1-inStart +1) root.right = index+1 > inEnd ? null: helper(preStart+ index-inStart +1, index+1, inEnd, preorder, inorder,map_in); return root; } }
106 和105类似,不再分析,代码如下:
class Solution { public TreeNode buildTree(int[] inorder, int[] postorder) { Map<Integer, Integer> map_in = new HashMap<>(); int len = postorder.length; for(int i=0; i<len; i++) map_in.put(inorder[i],i); return helper(len-1, 0,len-1, inorder, postorder, map_in) ; } private TreeNode helper(int poEnd, int inStart, int inEnd, int[] inorder, int[] postorder, Map<Integer,Integer> map_in){ if(inStart > inEnd) { //包含了了 order = []的情况了 return null; } TreeNode root = new TreeNode(postorder[poEnd]); int index = map_in.get(root.val); //System.out.println("poEnd: "+ poEnd + " inStart: "+ inStart+ " inEnd: "+ inEnd + " index: "+ index); root.left = helper(poEnd-inEnd+index-1, inStart, index-1, inorder, postorder, map_in); root.right = helper(poEnd-1, index+1,inEnd,inorder,postorder,map_in); return root; } }