题目
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
限制:
0 <= 节点个数 <= 5000
解题思路
- 二叉树的特点是什么?
- 每个节点最多有两棵子树,所以二叉树中不存在度大于2的节点。也可以没有左子树和右子树。
- 根据便利的特点来进行重建
- 前序遍历: 二叉树为空,则空操作返回,否则访问根节点,然后前序遍历左子树,再前序遍历右子树。这块就得注意了这就是插入点。
- 中序便利: 若树为空,则空操作返回,否则从根节点开始,中序遍历根节点的左子树,然后访问根节点,然后访问右子树。
- 通过回想这个两个遍历的特点,那开始重建
- 从中序便利中我们可以判断出根节点是哪一个,那就是前序遍历的preorder[0].
- 我们知道了根节点,哪我们可以根据中续遍历,就可以得出左子树和右子树。有哪些元素。
- 由于树中的节点数量与遍历方式无关,通过中序遍历得知左子树和右子树的节点数量之后,可以根据节点数量得到前序遍历中的左子树和右子树的分界,因此可以进一步得到左子树和右子树各自的前序遍历和中序遍历,可以通过递归的方式,重建左子树和右子树,然后重建整个二叉树。
代码
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
//如果前序遍历数组为空那这棵树也是空的
if(preorder == null ){
return null ;
}else{
//先拿到中序便利的数量
int length = inorder.length;
//通过Map记录中序遍历的值,在后面可以根据根节点拿到左子树和又字树的元素
Map<Integer,Integer> inorderMap = new HashMap<Integer,Integer>();
for(int i = 0 ;i<length;i++){
inorderMap.put(inorder[i],i);
}
// 构建一个树根据前序遍历和后续遍历的数组
//其实有人会问为什么要这样写这么多参数。因为我们要递归调用将其中的遍历的数组切开,然后去便利左子树右子树。
return buildTree(preorder,0,length-1,inorder,0,length-1,inorderMap);
}
}
public TreeNode buildTree(int [] preorder,int preorderStart,int preorderEnd,int[] inorder,int inoderStart, int inorderEnd,Map<Integer,Integer> inorderMap){
if(preorderStart>preorderEnd){
return null;
}
// 拿到根节点
int rootVal = preorder[preorderStart];
// 创建一颗有根节点的二叉树
TreeNode root = new TreeNode(rootVal);
if(preorderStart == preorderEnd){
return root;
}else{
拿到根节点在遍历数组中的位置
int rootIndex = inorderMap.get(rootVal);
// 左子树的节点数量
int leftNodes = rootIndex - inoderStart; 右子树节点的数量
int rightNodes = inorderEnd - rootIndex;
构建左子树
TreeNode leftSubtree = buildTree(preorder, preorderStart + 1, preorderStart + leftNodes, inorder, inoderStart, rootIndex - 1, inorderMap);
便利右子树
TreeNode rightSubtree = buildTree(preorder, preorderEnd - rightNodes + 1, preorderEnd, inorder, rootIndex + 1, inorderEnd, inorderMap);
//将左子树与右子树拼起来
root.left = leftSubtree;
root.right = rightSubtree;
}
return root;
}
}
总结
- 刚开始做这道题真的没有思路,于是就看一边答案,然后尝试自己慢慢去写,然后几经调试。就跑出来了。
- 核心思想就是中序遍历和前序遍历的算法。
- 还有就是理解左子树和右子树的便利过程
参考
- https://blog.csdn.net/My_Jobs/article/details/43451187
- https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/