输入某个二叉树的前序遍历、后序遍历的结果,请重建该二叉树(假设遍历结果中不包含重复元素)。
- 前序:{1,2,4,7,3,5,6,8}—根结点 1
- 中序:{4,7,2 ,1, 5,3,8,6}–左子树 4 7 2 —右子树 5 3 8 6
思路
递归对我而言比较难!整体思想在于对在中序遍历中的根结点的寻找,以及左右子树的递归中起始、终止索引位置理解上。
核心问题就是对计算中序遍历中左子树的元素数量进而对边界值做出判断。(rootIndexInMin-inStart)
的理解,instart
每递归一次就会变化。
递归这种问题要特别 关注形参、实参。
解法1-1
/**
* 面试题7:重建二叉树
* 输入某个二叉树的前序遍历、后序遍历的结果,请重建该二叉树(假设遍历结果中不包含重复元素)
* 递归只有当前状况和下一个状况!
*
* 前序:{1,2,4,7,3,5,6,8}---根结点 1
* 中序:{4,7,2 ,1, 5,3,8,6}--左子树 4 7 2 ---右子树 5 3 8 6
* @author Heroin X
* @date 2019/12/3 14:01
*/
public class RebuildBinaryTree {
public static void main(String[] args) {
int[] preOrder={1,2,4,7,3,5,6,8};
int[] inOrder={4,7,2,1,5,3,8,6};
TreeNode root= new RebuildBinaryTree().rebuild(preOrder,inOrder);
new RebuildBinaryTree().print(root);
}
private void print(TreeNode root) {
//判断条件!!!
if (root!=null){
print(root.leftNext);
System.out.print(root.data+" ");
print(root.rightNext);
}
}
TreeNode rebuild(int[] preOrder, int[] inOrder) {
if (preOrder==null||inOrder==null){
return null;
}
return rebuild(preOrder,0,preOrder.length-1,inOrder,0,inOrder.length-1);
}
/**
*
* @param preOrder 前序
* @param preStart 前序开始元素位置
* @param preEnd 前序结束位置
* @param inOrder 中序
* @param inStart 中序开始位置
* @param inEnd 中序结束位置
* @return 结点
*
* * 前序:{1,2,4,7,3,5,6,8}---根结点 1
* *
* * 中序:{4,7,2 ,1, 5,3,8,6}--左子树 4 7 2 ---右子树 5 3 8 6
*/
private TreeNode rebuild(int[] preOrder, int preStart, int preEnd, int[] inOrder, int inStart, int inEnd) {
//终止条件!!! 递归要注意出口,假设最后只有一个元素了,那么就要返回。
if (preStart>preEnd || inStart>inEnd){
return null;
}
//根结点
TreeNode root = new TreeNode(preOrder[preStart]);
int rootData = root.data;
//在中序遍历中找到根结点的位置,进而在前序遍历中找到左右子树元素
int rootIndexInMin=inStart;
while (rootIndexInMin<inEnd && inOrder[rootIndexInMin]!=rootData){
rootIndexInMin++;
}
// 前序:{1,2,4,7, 3,5,6,8}---根结点 1
// 中序:{4,7,2 ,1, 5,3,8,6}--左子树 4 7 2 ---右子树 5 3 8 6 4 7 2 1 5 3 8 6
// preStart=0 inStart=0
// rootIndexInMin=3
// root.leftNext=rebuild(preOrder,preStart+1,preStart+rootIndexInMin-inStart,inOrder,inStart,rootIndexInMin-1);
// root.rightNext=rebuild(preOrder,preStart+rootIndexInMin-inStart+1,preEnd,inOrder,rootIndexInMin+1,inEnd);
root.leftNext=rebuild(preOrder,preStart+1,preStart+rootIndexInMin-inStart,inOrder,inStart,rootIndexInMin-1);
root.rightNext=rebuild(preOrder,preStart+(rootIndexInMin-inStart)+1,preEnd,inOrder,rootIndexInMin+1,inEnd);
return root;
}
}
class TreeNode{
int data;
TreeNode leftNext;
TreeNode rightNext;
public TreeNode(int data) {
this.data = data;
}
public TreeNode() {
}
}
解法1-2-OJ
这一次做在坐标的点位是ok的,但是在对本题中的递归以及其他问题理解是模糊的,不清晰。
(1)错误1 和 错误2 的问题认识不深刻;
(2)错误3 关于递归终止条件比较薄弱。加强理解。if(node==null){ return node }
,然后报没有node的问题。甚至一度修改了方法参数。
(3)错误4关于中序遍历受到之前的直接打印的思路影响,在中序遍历的认识上还需要加强。
(4)递归的用时问题体现出来了。
nowcoder的AC
提交时间:2020-01-06 ,语言:Java ,运行时间: 239 ms ,占用内存:23000K ,状态:答案正确
/**
* Definition for binary tree
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
/**
* min{4,7,2, 1, 5,3,8,6}
* pre{1 ,2,4,7,3,5,6,8}
*/
public class Solution {
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
if(pre.length==0 || in.length==0){
return null;
}
int len=pre.length-1;
return reContructTree(pre,0,len,in,0,len);
}
public TreeNode reContructTree(int [] pre,int preStart,int preEnd,int [] in,int inStart,int inEnd) {
//recrusion end condtion,error3
if(preStart>preEnd||inStart>inEnd){
return null;
}
TreeNode head=new TreeNode(pre[preStart]);
// error1
int index=inStart;
// error2
while(index<inEnd && in[index]!=head.val){
index++;
}
//find the head in inOrder int lLen=index-inStart,int rLen=inEnd-index
int lLen=index-inStart;
int rLen=inEnd-index;
TreeNode node=head;
node.left=reContructTree(pre,preStart+1,preStart+lLen,in,inStart,index-1);
//node=node; error4
node.right=reContructTree(pre,preStart+lLen+1,preEnd,in,index+1,inEnd);
return node;
}
}