剑指Offer(第二版)面试题7:重建二叉树



(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/71684216冷血之心的博客)


剑指Offer面试题7:重建二叉树

题目:输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。
假设输入的前序遍历和中序遍历中都不包含重复的数字。例如前序遍历序列为{1,2,4,5,3,7,6}和中序遍历序列{4,2,5,1,7,3,6},则可以重建一棵二叉树。如图所示:

   1  
 /  \  
2     3  
       /  \    /  \  
     4   5  7  6  


思路:通过前序遍历序列可以得到根节点,中序遍历序列可以得到左右分别有哪些节点;通过,在左右子树中使用此方法进行递归,最后,可以重建二叉树。

已知二叉树的前序遍历和中序遍历:
PreOrder:           GDAFEMHZ
InOrder:            ADEFGHMZ

我们基于一个事实:中序遍历一定是 { 左子树中的节点集合 },root,{ 右子树中的节点集合 },前序遍历的作用就是找到每棵子树的root位置。

算法
输入:前序遍历,中序遍历
1、寻找树的root,前序遍历的第一节点G就是root。
2、观察前序遍历GDAFEMHZ,知道了G是root,剩下的节点必然在root的左或右子树中的节点。
3、观察中序遍历ADEFGHMZ。其中root节点G左侧的ADEF必然是root的左子树中的节点,G右侧的HMZ必然是root的右子树中的节点,root不在中序遍历的末尾或开始就说明根节点的两颗子树都不为空。
4、观察左子树ADEF,按照前序遍历的顺序来排序为DAFE,因此左子树的根节点为D,并且A是左子树的左子树中的节点,EF是左子树的右子树中的节点。
5、同样的道理,观察右子树节点HMZ,前序为MHZ,因此右子树的根节点为M,左子节点H,右子节点Z。



import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/*
 * 剑指Offer面试题7:重建二叉树
 * 题目:输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。
 * 假设输入的前序遍历和中序遍历中都不包含重复的数字。例如前序遍历序列为{1,2,4,5,3,7,6}
 * 和中序遍历序列{4,2,5,1,7,3,6},则可以重建一棵二叉树。如图所示:
 *  
		    1  
		  /  \  
		 2    3  
		/ \  / \  
	   4  5 7   6  
	  
 */
public class Test {

	public static void main(String[] args) {
		TreeNode root = new TreeNode(1);  
        TreeNode r2 = new TreeNode(2);  
        TreeNode r3 = new TreeNode(3);  
        TreeNode r4 = new TreeNode(4);  
        TreeNode r5 = new TreeNode(5);  
        TreeNode r6 = new TreeNode(6);
        TreeNode r7 = new TreeNode(7);
          
        root.left = r2;  
        root.right = r3;  
        r2.left = r4;  
        r2.right = r5;  
        r3.right = r6; 
        r3.left = r7;
        List<Integer> preList = new ArrayList<>();
        preList.add(1);
        preList.add(2);
        preList.add(4);
        preList.add(5);
        preList.add(3);
        preList.add(7);
        preList.add(6);
        
        List<Integer> inList = new ArrayList<>();
        inList.add(4);
        inList.add(2);
        inList.add(5);
        inList.add(1);
        inList.add(7);
        inList.add(3);
        inList.add(6);
        
        
        TreeNode reBuildTree = reBuildTree(preList, inList);
        levelTraversal(reBuildTree);
        
	}
	/**
	 * 思路:使用递归的思路解决问题,分别在左右子树中进行操作
	 * @param preOrderList
	 * @param inOrderList
	 * @return
	 */
	private static TreeNode reBuildTree(List<Integer> preOrderList,List<Integer> inOrderList){
		if(preOrderList==null||inOrderList==null)
			return null;
		TreeNode root = null; // 要返回的根结点
		List<Integer> leftPreOrderList;
		List<Integer> rightPreOrderList;
		List<Integer> leftInOrderList;
		List<Integer> rightInOrderList;
		int inOrderPos;
		int preOrderPos;
		
		if(preOrderList.size()!=0&&inOrderList.size()!=0){
			// 把preorder的第一个元素作为root  
			root = new TreeNode(preOrderList.get(0));
			// 因为知道root节点了,所以根据root节点位置,把preorder,inorder分别
            //划分为 root左侧 和 右侧 的两个子区间  
			inOrderPos = inOrderList.indexOf(preOrderList.get(0));   // inorder序列的分割点 
			leftInOrderList = inOrderList.subList(0, inOrderPos);
			rightInOrderList = inOrderList.subList(inOrderPos+1, inOrderList.size());
			
			preOrderPos = leftInOrderList.size();  // preorder序列的分割点
			leftPreOrderList = preOrderList.subList(1, preOrderPos+1);
			rightPreOrderList = preOrderList.subList(preOrderPos+1, preOrderList.size());
			// root的左子树就是preorder和inorder的左侧区间而形成的树  
			root.left = reBuildTree(leftPreOrderList, leftInOrderList);
			// root的右子树就是preorder和inorder的右侧区间而形成的树  
			root.right = reBuildTree(rightPreOrderList, rightInOrderList);
			
		}
		return root;
		
	}
	/**
	 * 分层遍历二叉树,使用一个队列,也就是宽度优先遍历
	 * @param root
	 */
	public static void levelTraversal(TreeNode root){
    	if(root==null)
    		return ;
    	
    	LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
    	queue.add(root);
    	while(!queue.isEmpty()){
    		TreeNode cur = queue.remove();
    		System.out.print(cur.val+" ");
    		if(cur.left!=null)
    			queue.add(cur.left);
    		if(cur.right!=null)
    			queue.add(cur.right);
    		
    	}
    }
	

	
}
//建立二叉树节点类
class TreeNode{
	int val;
	TreeNode left;
	TreeNode right;
	public TreeNode(int val){
		this.val = val;
	}
	
}


参数为数组时:

public TreeNode reConstructBinaryTree(int[] pre,int[] in) {
        if(pre==null||in==null)
        	return null;
        TreeNode root = null;
       
        int[] preLeft = null;
        int[] preRight = null;
        
        int[] inLeft = null;
        int[] inRight = null;
        
        if(pre.length!=0&&in.length!=0){
        	// 得到root节点
        	root = new TreeNode(pre[0]);
        	for (int i = 0; i < in.length; i++) {
				if(pre[0]==in[i]){
					inLeft = Arrays.copyOfRange(in, 0, i);
					inRight = Arrays.copyOfRange(in, i+1, in.length);
					preLeft = Arrays.copyOfRange(pre, 1, i+1);
					preRight = Arrays.copyOfRange(pre, i+1, pre.length);
				}
			}
        	root.left = reConstructBinaryTree(preLeft, inLeft);
        	root.right = reConstructBinaryTree(preRight, inRight);
        	
        }
        return root;
    }

此时需要用到Arrays.copyRange(int[ ]  original , int from, int end)



如果对你有帮助,记得点赞哦~欢迎大家关注我的博客,可以进群366533258一起交流学习哦~




阅读更多

扫码向博主提问

温柔狠角色

博客专家

非学,无以致疑;非问,无以广识
去开通我的Chat快问
版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/qq_25827845/article/details/71684216
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭