题目链接:https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
题目:
Given preorder and inorder traversal of a tree, construct the binary tree.
Note:
You may assume that duplicates do not exist in the tree.
解题思路:
这道题是第二次做了,在《剑指Offer》上也有同样的题目。
思路是:
- 顺序遍历前序数组
- 每遍历到一个元素,就以该元素为根,找到中序遍历数组中相同的元素,以该元素为界,将数组切分成两份,根左边的元素属于左子树,根右边的元素属于右子树
- 递归找到左子树和右子树的根元素
- 最后把左子树和右子树接到根元素上,形成一棵完整的树
在中序遍历数组中查找根元素时,我使用的是对数组的线性遍历。这种做法时间耗费较大。
看了大神的做法,他是将中序遍历数组映射到一个 HashMap 中,以数组元素为键,数组下标为值。这样,在中序遍历数组找根元素时,就能在常数时间完成。
下面补充大神的详细思路:
http://blog.youkuaiyun.com/linhuanmars/article/details/24389549
假设树的先序遍历是 12453687,中序遍历是 42516837。
- 这里最重要的一点就是先序遍历可以提供根的所在,而根据中序遍历的性质知道根的所在就可以将序列分为左右子树。
- 比如上述例子,我们知道 1 是根,所以根据中序遍历的结果 425 是左子树,而 6837 就是右子树。
- 接下来根据切出来的左右子树的长度又可以在先序便利中确定左右子树对应的子序列(先序遍历也是先左子树后右子树)。
- 根据这个流程,左子树的先序遍历和中序遍历分别是 245 和 425,右子树的先序遍历和中序遍历则是 3687 和 6837,我们重复以上方法,可以继续找到根和左右子树,直到剩下一个元素。
- 可以看出这是一个比较明显的递归过程,对于寻找根所对应的下标,我们可以先建立一个HashMap,以免后面需要进行线行搜索,这样每次递归中就只需要常量操作就可以完成对根的确定和左右子树的分割。
- 算法最终相当于一次树的遍历,每个结点只会被访问一次,所以时间复杂度是O(n)。而空间我们需要建立一个map来存储元素到下标的映射,所以是O(n)。
补充:这题的难点在于正确切分子树的下标位置。
测试用例可以选用 3 个节点的 5 种不同构的树。
自己的代码实现:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder == null || preorder.length == 0 || inorder == null || inorder.length == 0 || preorder.length != inorder.length)
return null;
return helper(preorder, 0, inorder, 0, inorder.length - 1);
}
TreeNode helper(int[] preorder, int startPre, int[] inorder, int startIn, int endIn) {
TreeNode root = null;
for(int i = startIn; i <= endIn; i ++) {
if(inorder[i] == preorder[startPre]) {
root = new TreeNode(preorder[startPre]);
root.left = helper(preorder, startPre + 1, inorder, startIn, i - 1);
root.right = helper(preorder, i - startIn + 1 + startPre, inorder, i + 1, endIn);
break;
}
}
return root;
}
}
202 / 202 test cases passed.
Status: Accepted
Runtime: 22 ms
推荐大神的解法:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder==null || inorder==null)
return null;
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
for(int i=0;i<inorder.length;i++)
{
map.put(inorder[i],i);
}
return helper(preorder,0,preorder.length-1,inorder,0,inorder.length-1, map);
}
private TreeNode helper(int[] preorder, int preL, int preR, int[] inorder, int inL, int inR, HashMap<Integer, Integer> map)
{
if(preL>preR || inL>inR)
return null;
TreeNode root = new TreeNode(preorder[preL]);
int index = map.get(root.val);
root.left = helper(preorder, preL+1, index-inL+preL, inorder, inL, index-1, map);
root.right = helper(preorder, preL+index-inL+1, preR, inorder, index+1, inR,map);
return root;
}
}
202 / 202 test cases passed.
Status: Accepted
Runtime: 5 ms