重建二叉树
题目
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
思路
1. 递归
抓住核心找根节点
综合上面的介绍树的遍历方式,我们发现前序遍历的第一个节点必然是这棵树的根节点。而在中序遍历中,由于其特殊的访问顺序规则根节点总是在中间,处于根节点左边则是左子树的节点集合,而处于根节点右边则是右子树的节点集合。所以我们根据根节点找出左右子树后,又可以对左右子树按照同样的思路来处理。因此此处采用递归非常合适。
下面我们结合例子,简单复述一下上面的处理过程。
前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}。
- 根据前序遍历的第一个节点,我们可以知道这课树的根节点为1.
- 然后我们在中序遍历中找到我们的根节点1所处的位置,position = 3
- 我们得出根节点1的左子树节点集合为{4,7,2}。右子树的节点集合为{5,3,8,6}
- 接下来我们处理左子树,同样根据前序遍历可知左子树集合4,7,2的根节点为2,因为树的前序遍历的第一个节点必为根节点呀。
- 然后我们在中序遍历中找到我们的根节点2所处的位置,position = 2
- 我们得出根节点2的左子树节点集合为{4,7}。右子树的节点集合为为空,说明该节点没有右子树。
- 之后我们继续按如下的操作的处理左子树集合{4,7}
………
按照以上步骤,最终就会重构出我们的二叉树。这里可以发现只要子树的区间大小变为0了,说明父节点没有对应的子树,因此就不必继续递归处理,而是开始回溯。还有一点,我们是按照先左后右的递归处理,所以前序遍历中的每次都是按顺序去取来作为根节点的。所以可以用一个全局的index来控制前序的访问位置即可。我们只需关注中序遍历中每次划分的区间大小即可。
public class Solution {
static int index;
public static TreeNode reConstructBinaryTree(int[] pre, int[] in) {
index = 0; //必须加这行,否则会失败,是答题系统问题? index 初始化不是0吗?
int len = pre.length;
return reConstructBinaryTree(pre, in, 0, len - 1);
}
public static TreeNode reConstructBinaryTree(int[] pre, int[] in, int s, int e) {
TreeNode treeNode = null;
if (s <= e) {
treeNode = new TreeNode(pre[index]);
int i = getiByVal(pre[index++], in, s, e);
treeNode.left = reConstructBinaryTree(pre, in, s, i - 1);
treeNode.right = reConstructBinaryTree(pre, in, i + 1, e);
}
return treeNode;
}
public static int getiByVal(int val, int[] in, int s, int e) {
for (int i = s; i <= e; i++) {
if (val == in[i]) {
return i;
}
}
return -1;
}
}