[LeetCode] Construct Binary Tree from Preorder and Inorder Traversal

来源:互联网 发布:vasp软件下载 编辑:程序博客网 时间:2024/06/15 14:15

Given preorder and inorder traversal of a tree, construct the binary tree.

Note:
You may assume that duplicates do not exist in the tree.

这题不难,突破点是抓住前序遍历和中序遍历的本质:前序遍历中的第一个访问节点必须是根节点,然后是左右子树;中序遍历中先访问左子树,然后根节点,最后右子树。

因此,递归思路是:

1)前序遍历第一个节点为根节点,根据这个根节点的值,在中序遍历中寻找根节点位置,然后就可以找到对应左右子树的序列。根据序列的长度,可以找到在前序遍历中的对应序列。

2)如果序列长度为0,则可以返回null。


下面先给出一个易于理解大众化解法:


public TreeNode buildTree(int[] preorder, int[] inorder) {if (inorder.length == 0)return null;TreeNode root = new TreeNode(preorder[0]);for (int i = 0; i < inorder.length; i++) {if (inorder[i] == root.val) {int rootIndex = i;root.left = buildTree(Arrays.copyOfRange(preorder, 1, rootIndex + 1),Arrays.copyOfRange(inorder, 0, rootIndex));root.right = buildTree(Arrays.copyOfRange(preorder,rootIndex + 1, preorder.length), Arrays.copyOfRange(inorder, rootIndex + 1, inorder.length));}}return root;}

在没有另外改变函数接口的情况下,由于我使用的Java,传递子数组时不能直接传递数组的首地址,所以这里每次传递都把子数组拷贝了一份,效率很低。此外,可以发现在中序遍历中查找跟节点时,我使用的是线性查找,所以查找开销是O(N)。注意这里没说是二叉搜索树,所以输入的序列并没有按值的大小排序,无法使用二分搜索。

分析算法复杂度,如果二叉树非常平衡的话,那么循环会执行logN次,总时间复杂度大约是O(NlogN)。但是,如果二叉树非常的倾斜,例如二叉树是一条直线的最坏情况下,循环会执行N次,那么总时间复杂度将会是O(N^2)。


其实以上代码虽然可以过LeetCode的测试,但是效率还是很低的。可以做两个改进:

1)对于Java这样无法传数组首地址的语言,可以另外声明函数然后调用,避免拷贝数组元素的开销;

2)建立哈希表,把在中序遍历总搜索根节点的线性查找时间降低到O(1)。

public TreeNode buildTree(int[] preorder, int[] inorder) {if (inorder.length == 0)return null;// construct a look-up table for searching the inorder indexHashMap<Integer, Integer> inorderIndices = new HashMap<Integer, Integer>();for (int i = 0; i < inorder.length; i++) {inorderIndices.put(inorder[i], i);}TreeNode root = buildTree(preorder, 0, inorder, 0, preorder.length,inorderIndices);return root;}private TreeNode buildTree(int[] preorder, int start1,int[] inorder, int start2, int treeLen,HashMap<Integer, Integer> inorderIndices) {if (treeLen <= 0) {return null;}TreeNode root = new TreeNode(preorder[start1]);int rootIndex = inorderIndices.get(preorder[start1]);int leftSubtreeLen = rootIndex - start2;int rightSubtreeLen = treeLen - leftSubtreeLen - 1;root.left = buildTree(preorder, start1 + 1, inorder, start2,leftSubtreeLen, inorderIndices);root.right = buildTree(preorder, start1 + 1 + leftSubtreeLen, inorder,rootIndex + 1, rightSubtreeLen, inorderIndices);return root;}

这样一来,在二叉树平衡的情况下,时间复杂度为O(logN),最坏情况为O(N)。

LeetCode上还有一题非常的类似,是给出中序遍历和后序遍历的序列。值得一提的是,前序遍历和后续遍历两个序列是无法用来构造二叉树的。


0 0
原创粉丝点击