问题描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
解题思路
/**
* Definition for binary tree
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
/**
* 前提:树的每个节点的值不重复
* 思路:
* 利用递归的思想,为什么想到递归呢?
*
* 前序数组的第一个是根节点,记为i,在中序数组中找到它,
* 则中序数组中i的左边明显是根节点的“左子树的中序遍历”,长度记为r,
*
* 而我们也可以找到“左子树的前序遍历”,
* 这需要在前序数组中根节点右边开始算的r个元素为左子树的前序遍历
*
* 接着,我们还可以寻找“右子树的中序遍历”,很明显,中序数组中i的右边就是
* 剩下,我们寻找“右子树的前序遍历”,在前序数组中找,中序数组中i的右边的长度记为m,
* 则前序数组中i的倒数m个元素就是我们要找的“右子树前序遍历”
*
* 看完这些,你应该大概能理解,为什么用递归了,
* 因为我们每次都是能很明确的从前序数组中找到树的根节点,
* 根节点需要left指向左子树根,right需要指向右子树根,所以可以通过递归不断求根,直到没有子树,就构建完一棵二叉树。
*/
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
return reConstructBinaryTreeInterval(pre, 0, pre.length - 1, in, 0, in.length -1);
}
/**
* 参数说明:
* pre 原本前序数组
* preI 树的前序遍历在前序数组中的起始下标
* preJ 树的前序遍历在前序数组中的结束下标
* in 原本的中序数组
* inI 树的中序遍历在中序数组的起始下标
* inJ 树的中序遍历在中序数组的结束下标
*/
private TreeNode reConstructBinaryTreeInterval(int[] pre, int preI, int preJ,
int[] in, int inI, int inJ) {
// 结束条件,也就是没有子树的情况,返回null
if(preI > preJ || inI > inJ) {
return null;
}
// 构建根节点
TreeNode head = new TreeNode(pre[preI]);
// 在中序数组中找到根节点的位置
int position = -1;
for(int i = inI; i <= inJ; i++) {
if(pre[preI] == in[i]) {
position = i;
break;
}
}
// 计算出左子树有多少个节点,
int r = position - inI;
//递归构建左子树,需要在前序数组中找到左子树的前序序列范围--> preI + 1开始 到preI + r
//和中序数组中找到左子树的中序遍历范围--> inI开始到position -1
head.left = reConstructBinaryTreeInterval(pre, preI + 1, preI + r, in, inI, position - 1);
//递归构建右子树,需要在前序数组中找到右子树的前序序列范围--> preI + r + 1开始,到preJ
// 和中序数组中找到右子树的中序遍历范围--> position + 1 到 inJ
head.right = reConstructBinaryTreeInterval(pre,preI + r + 1, preJ, in, position + 1, inJ);
return head;
}
}
根据上面利用前序数组和中序数组重建二叉树的思路,可以总结出根据后序-中序数组重建的过程,以及前序-后序数组重建过程。
后序-中序 重建
后序数组的特点是根节点就是数组的最后一个元素。
我们只要得到下面这些信息,就好办了
- 得出左子树的后序序列在后序数组的下标范围
- 得出左子树的中序序列在中序数组的下标范围
- 得出右子树的后序序列在后序数组的下标范围
- 得出右子树的中序序列在中序数组的下标范围
1. 得出左子树的中序序列在中序数组的下标范围
中序序列数组中根节点左边的就是是左子树的中序遍历序列。同时可以得出左子树的长度。
2. 得出左子树的后序序列在后序数组的下标范围
后序数组中前N个元素就是左子树的后序序列,而上面已经可以求得这个N,也就可以算出下标范围了。
3. 得出右子树的中序序列在中序数组中的下标范围
中序数组中根节点的右边就是右子树的中序遍历序列, 因而下标范围可求。
4. 得出右子树的后序序列在后序数组中的下标范围
后序数组中前N个元素是左子树的后序序列,而剩下下标为N开始的到后序数组末尾不包括末尾,就是要求的下标范围。
对比上面的代码,你很快就能写出中序-后序的构建过程。
前序-后序 重建
前序-后序重建其实并不一定能重建一棵二叉树,有时候前序和后序序列并不能唯一确定一棵二叉树。
比如:头节点 为1, 左孩子为2,无右孩子,这时前序遍历:【1,2】;后序遍历:【2,1】。另一种情况,头节点为1,右孩子为2,无左孩子,这时前序和后序也是【1,2】和【2,1】。
因此,仅根据前序和后序序列是无法重建一棵二叉树的。
网友评论