一、需求
- 根据一棵树的前序遍历与中序遍历构造二叉树。
例如,给出
前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3 / \ 9 20 / \ 15 7
注意:
你可以假设树中没有重复的元素。
二、递归法
2.1 思路分析
- 前序遍历的特点是"根左右",中序遍历的特点是"左根右",通过前序遍历和中序遍历可以唯一确定一棵二叉树;
- 利用根节点将preorder与inorder数组分别分成两半,这样原问题就变成了规模更小的子问题,即得到了根节点,左子树的前序遍历、左子树的中序遍历,右子树的前序遍历,右子树的中序遍历,按照1的说法,左子树和右子树也是唯一确定的;
- 接下来的问题是如何将数组分成两半呢?找到根节点很容易,它是preorder的第一个值,然后找到根节点在中序遍历中的索引,这样就可以确定前序遍历中左子树的边界、右子树的边界,中序遍历中左子树的边界、右子树的边界;
2.2 代码实现
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
return buildTree(preorder, 0, preorder.length - 1, inorder, 0,
inorder.length -1);
}
//该方法根据前序与中序遍历递归的构造二叉树
private TreeNode buildTree(int[] preorder, int preStart, int preEnd,
int[] inorder, int inStart, int inEnd) {
//这里可以用inStart、inEnd代替吗?当然可以,因为在划分数组时,前序与中序总是相对应
if(preStart > preEnd) {
return null;
}
//获取当前根节点
int rootVal = preorder[preStart];
//确定根节点在中序遍历中的索引
int index = 0;
for(int i = inStart; i <= inEnd; i++) {
if(inorder[i] == rootVal) {
index = i;
break;
}
}
//确定左子树节点的个数
int leftSize = index - inStart;
//构建二叉树
TreeNode root = new TreeNode(rootVal);
root.left = buildTree(preorder, preStart+1, preStart+leftSize,
inorder, inStart, index - 1);
root.right = buildTree(preorder, preStart+leftSize+1, preEnd,
inorder, index + 1, inEnd);
return root;
}
}
2.3 复杂度分析
- 时间复杂度为O(N);
- 空间复杂度为O(N);