{1,2,4,7,3,5,6,8}
和中序遍历序列{4,7,2,1,5,3,8,6}
,则重建二叉树并返回。思路及解法:
递归解决:
在保证数据正确性的前提下,前序的第一个数值是root节点,即上图中的1,那么我们需要在中序遍历中找到1的位置,左边的就是root的左子树,右边是root的右子树。
定义:
Definition for binary tree
public class TreeNode{
int val;
TreeNode left;
TreeNode right;
TreeNode(int x){
val = x;
}
}
Java代码实现:
pubilc class Solution{
public TreeNode reConstructBinaryTree(int[] pre,int[] in){
if(pre == null || pre.length == 0 || in == null || in.length == 0){
return null;
}
TreeNode root = constructBinaryTree(pre,0,pre.length - 1,in,0,in.length - 1);
return root;
}
TreeNode constructBinaryTree(int[] pre,int startPre,int endPre,int[] in, int startIn, int endIn){
//不符合条件直接返回null
if(startPre > endPre || startIn > endIn){
return null;
}
//构建根节点
TreeNode root = new TreeNode(pre[startPre]);
for(int index = startIn ; index <= endIn; index++){
if(in[index] == pre[startPre]){
//左子树
root.left = constructBinaryTree(pre,startPre + 1,startPre + (index - startIn),in, startIn, index -1);
//右子树
root.right = constructBinaryTree(pre,(index - startIn) + startPre + 1,endPre, in,index + 1,endIn);
break;
}
}
return root;
}
}
栈的解法: 我们可以一开始创建一个栈,分别用两个指针执行前序遍历和中序遍历的第一个元素,先将前序遍历的第一个元素压入栈中,因为前序遍历的特性,第一个元素肯定是根节点。
开始循环,对比栈顶的元素和中序遍历数组的元素
图示如下:
把当前的前序遍历的元素1先放到栈里面,这个是根节点:
对比中序遍历第一个元素
4
,和栈顶元素1
,不相等,那么说明有左子树,前序遍历的第 2 个元素2
就是左子树节点,关联成左子树,压栈:
不相等,继续压栈:
中序遍历的第一个元素
4
,已经等于栈顶元素4
,说明4
没有左子树了,因为4
是在中序遍历里面,中序遍历完根节点,剩下的部分只能是右子树。那么把4
弹出去,中序遍历指针移动到下一个位置:
这个时候,
7
肯定是之前节点4
的右子树节点,那么关联关系之后,压入栈里面:
此时,结束了一次循环,注意前序遍历的指针会往后移动一位。
再次循环的时候,依然判断中序遍历中的数值是否等于栈顶元素,发现都是
7
,相等。弹出,移动到下一个位置,相当于退出了上一层:
依旧
2==2
相等,再次弹出:
同样中序遍历的
1
还是等于栈顶的1
,弹出,移动到下一位:
这个时候,栈顶元素的
1
已经被取出来了,说明左子树全部遍历完成了,剩下的部分是它的右子树内容了,那么前序遍历中,3
就必定是根节点1
的右子树的根,压入栈中,前序遍历索引指向下一个元素:
到这里其实是结束了第二轮的循环。再次循环,判断中序遍历的数值和栈顶元素不相等,那么说明是左子树,前序遍历中的
5
压入栈内,索引后移:
中序遍历的数值和栈顶元素一对比,发现相等,说明
5
没有左子树了,弹出,索引后移:
依然 两个都是 3(说明 3 的左子树被遍历完成了,剩下的是
3
的右子树了),继续弹出,后移
此时,
3
是刚刚弹出的元素,剩下的元素都是它的右子树,那么前序遍历中指向的数组6
就是3
的右子树,6
压入栈中:
对比栈顶元素
6
和中序遍历中的8
发现不相等,那么把前序遍历中的8
压栈,成为左子树:
对比栈顶元素
8
和中序遍历的8
,相等则弹出:
还是相等,继续弹出:
Java代码实现:
import java.util.Stack;
class TreeNode{
int val;
TreeNode left;
TreeNode right;
TreeNode(int x){
val = x;
}
}
public class Solution{
public TreeNode reConstructBinaryTree(int[] pre,int[] in){
//判空
if(pre == null || pre.length == 0 || in == null || in.length ==0){
return null;
}
Stack stack = new Stack<>();
int preIndex = 0;
int inIndex = 0;
TreeNode root = new TreeNode(pre[preIndex]);
stack.push(root);
for(preIndex = 1 ; preIndex < pre.length ; preIndex++){
TreeNode node = stack.peek();
//不相等说明还有左子树
if(node.val != in[inIndex]){
//关联成为左子树,压栈
node.left = new TreeNode(pre[preIndex]);
stack.push(node.left);
}
else{
//相等说明。当前节点没有左子树
while(!stack.isEmpty() && stack.peek().val == in[Index]){
//只要两者相等,说明没有右子树,弹出节点,退到上一层
node = stack.pop();
inIndex++;
}
//有右子树,关联
node.right = new TreeNode(pre[preIndex]);
stack.push(node.right)
}
}
return root;
}
}
总结:本题的解题关键在于,理解并熟练掌握数据结构中关于二叉树的三种遍历方式:前序遍历(NLR)、中序遍历(LNR)以及后序遍历(LRN),通过已知条件:先序序列和中序序列来重新构造一个完整的二叉树。