剑指Offer+第39题+二叉树的深度+java

题目(问题1):输入一棵二叉树的根节点,求该数的深度。从根节点到叶结点依次进过的结点(含根,叶结点)形成树的一条路径,最长路径的长度为树的深度。

例如,如下图的二叉树的深度为4,因为它从根节点到叶结点的最长的路径包含4个结点(从根结点1开始,经过2和结点5,最终到达叶结点7)

我们可以从另一种角度来理解树的深度。如果一棵树只有一个结点,它的深度为1,如果根节点只有左子树而没有右子树,那么树的深度应该是其左子树的深度+1.同样如果根节点只有右子树而没有左子树,那么树的深度应该是其右子树+1.如果既有左子树又有右子树,那概述的深度就是左、右子树的深度的较大值加1.。

如果公司对编程能力有较高的要求,面试官可能会追加一个与前面的问题相关但难度较大的问题,比如,应聘者做完上面的问题后,面试官追问:


题目二:输入一棵二叉树的根节点,判断该树是不是平衡的二叉树。如果某二叉树中任意结点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。

方法1(看代码),每个节点遍历多次

需要重复遍历结点多次的解法,简单但不足以打动面试官

有了求二叉树的深度的经验之后再解决这个问题,我们很容易就能想到一个思路:在遍历树的每个结点的时候,调用函数TreeDepth得到它的左右子树的深度。如果每个结点的左右子树的深度相差不超过1,按照定义它就是一棵平衡的二叉树。
 

方法2(看代码):每个节点遍历一次,后序遍历

但我们也注意到由于一个结点会被重复遍历多次,这种思路的时间效率不高。例如在函数isBalanced中输入上图中的二叉树,我们将首先判断根节点是不是平衡的。此时我们网函数TreeDepth输入左子树的根节点时需要遍历结点4,5,7.接下来判断以结点2为根节点的子树是不是平衡树的时候,仍然会遍历结点4,5,7.毫无疑问,重复遍历同一个结点会影响性能。接下来我们寻找不需要重复遍历的算法。
每个结点只遍历一次的解法,正是面试官喜欢的算法

如果我们用后序遍历的方式遍历二叉树的每个结点,在遍历一个结点之前我们就已经遍历了它的左右子树。只要在遍历每个结点的时候我们记录它的深度(某一节点的深度等于它到叶结点的路径的长度),我们就可以一边遍历一边判断每个结点是不是平衡二叉树。
 

代码:

public class Offer39 {

	public static class BinaryTreeNode{
		int value;
		BinaryTreeNode left;
		BinaryTreeNode right;
		
		BinaryTreeNode(){}
		
		BinaryTreeNode(int val){
			this.value = val;
		}
	}
	
	//问题1,求二叉树的深度
	public int treeDepth(BinaryTreeNode root){
		if(root == null)
			return 0;
		int nLeft = treeDepth(root.left);
		int nRight = treeDepth(root.right);
		
		return (nLeft>nRight) ? (nLeft+1):(nRight+1);
	}
	
	//问题2.输入一个二叉树的根节点,判断该树是不是平衡二叉树
	//方法1,需要重复遍历节点多次的解法,不好
	public boolean isBalanced(BinaryTreeNode root){
		if(root == null)
			return true;
		
		int left = treeDepth(root.left);
		int right = treeDepth(root.right);
		int diff = left - right;
		if(diff>1 || diff<-1)
			return false;
		
		return isBalanced(root.left)&&isBalanced(root.right);
	}
	
	//方法2,每个基点只遍历一次的解法,后序遍历二叉树
	//高效率的判断是否是一棵平衡二叉树,照着课本上的c++代码翻译成java代码会出错,因为书中是&left,是引用传值,java中没有,这里用新建一个类解决这个问题
	public static class reference{
		private boolean isBalanced;
		private int depth;
		
		public reference(){}
		
		public reference(boolean isBalanced, int depth){
			super();
			this.isBalanced = isBalanced;
			this.depth = depth;
		}

		public boolean getIsBalanced() {
			return isBalanced;
		}

		public void setBalanced(boolean isBalanced) {
			this.isBalanced = isBalanced;
		}

		public int getDepth() {
			return depth;
		}

		public void setDepth(int depth) {
			this.depth = depth;
		}
	}
	
	public reference isBalanced2(BinaryTreeNode root){
		if(root == null){
			reference re = new reference();
			re.setBalanced(true);
			re.setDepth(0);
			return re;
		}
		
		reference left = isBalanced2(root.left);
		reference right = isBalanced2(root.right);
		
		if(left.getIsBalanced()&& right.getIsBalanced()){
			int diff = left.getDepth() - right.getDepth();
			if(diff<=1&& diff>=-1)
				return new reference(true,(left.getDepth()>right.getDepth() ? left.getDepth() : right.getDepth())+1);
		}
		return new reference(false, -1);
		
	}
	
	
	public static void setBinaryTreeNode(BinaryTreeNode root,BinaryTreeNode left, BinaryTreeNode right){
		if(root == null)
			return;
		root.left = left;
		root.right = right;
	}
	
	public static void main(String[] args) {
		
		Offer39 of39 = new Offer39();
		/*
		//功能测试,1,输入普通的二叉树
		//            1
		//         /      \
		//        2        3
		//       /\         \
		//      4  5         6
		//        /
		//       7
		BinaryTreeNode node11 = new BinaryTreeNode(1);
		BinaryTreeNode node12 = new BinaryTreeNode(2);
		BinaryTreeNode node13 = new BinaryTreeNode(3);
		BinaryTreeNode node14 = new BinaryTreeNode(4);
		BinaryTreeNode node15 = new BinaryTreeNode(5);
		BinaryTreeNode node16 = new BinaryTreeNode(6);
		BinaryTreeNode node17 = new BinaryTreeNode(7);
		
		setBinaryTreeNode(node11, node12, node13);
		setBinaryTreeNode(node12, node14, node15);
		setBinaryTreeNode(node15, node17, null);
		setBinaryTreeNode(node13, null, node16);
		
		System.out.println(of39.treeDepth(node11));
		
		//功能测试
		 // 02.二叉树的所有节点都没有左子树
	    //                  1                      
	    //                      \                    
	    //                       3                 
	    //                         \           
	    //                         6
		BinaryTreeNode node21 = new BinaryTreeNode(1);
		BinaryTreeNode node23 = new BinaryTreeNode(3);
		BinaryTreeNode node26 = new BinaryTreeNode(6);
		
		setBinaryTreeNode(node21, null, node23);
		setBinaryTreeNode(node23, null, node26);
		
		System.out.println(of39.treeDepth(node21));
		
		//功能测试
		 // 03.二叉树的所有节点都没有右子树
	    //                 1                     
	    //              /                             
	    //             2                             
	    //           /                                   
	    //          4  
		BinaryTreeNode node31 = new BinaryTreeNode(1);
		BinaryTreeNode node32 = new BinaryTreeNode(2);
		BinaryTreeNode node34 = new BinaryTreeNode(4);
		
		setBinaryTreeNode(node31, node32, null);
		setBinaryTreeNode(node32, node34, null);
		
		System.out.println(of39.treeDepth(node31));
		
		//特殊输入测试
		 // 04.只有一个节点的二叉树
	    //                  1
		BinaryTreeNode node41 = new BinaryTreeNode(1);
		
		setBinaryTreeNode(node41, null, null);
		
		System.out.println(of39.treeDepth(node41));
		
		//特殊输入测试,5
		//指向二叉树的根节点的指针为NULL
		BinaryTreeNode node51 = null;
		System.out.println(of39.treeDepth(node51));
		*/
		
		//功能测试,1,平衡的二叉树
		//            1
		//         /      \
		//        2        3
		//       /\         \
		//      4  5         6
		//        /
		//       7
		BinaryTreeNode node11 = new BinaryTreeNode(1);
		BinaryTreeNode node12 = new BinaryTreeNode(2);
		BinaryTreeNode node13 = new BinaryTreeNode(3);
		BinaryTreeNode node14 = new BinaryTreeNode(4);
		BinaryTreeNode node15 = new BinaryTreeNode(5);
		BinaryTreeNode node16 = new BinaryTreeNode(6);
		BinaryTreeNode node17 = new BinaryTreeNode(7);
		
		setBinaryTreeNode(node11, node12, node13);
		setBinaryTreeNode(node12, node14, node15);
		setBinaryTreeNode(node15, node17, null);
		setBinaryTreeNode(node13, null, node16);
		
		//System.out.println(of39.isBalanced(node11));
		System.out.println(of39.isBalanced2(node11).getIsBalanced());
		
		//功能测试,2,不平衡的二叉树
		//            1
		//         /      \
		//        2        3
		//       /\         \
		//      4  5         6
		//        /
		//       7
		//      /
		//     8
		BinaryTreeNode node21 = new BinaryTreeNode(1);
		BinaryTreeNode node22 = new BinaryTreeNode(2);
		BinaryTreeNode node23 = new BinaryTreeNode(3);
		BinaryTreeNode node24 = new BinaryTreeNode(4);
		BinaryTreeNode node25 = new BinaryTreeNode(5);
		BinaryTreeNode node26 = new BinaryTreeNode(6);
		BinaryTreeNode node27 = new BinaryTreeNode(7);
		BinaryTreeNode node28 = new BinaryTreeNode(8);
		
		setBinaryTreeNode(node21, node22, node23);
		setBinaryTreeNode(node22, node24, node25);
		setBinaryTreeNode(node25, node27, null);
		setBinaryTreeNode(node27, node28, null);
		setBinaryTreeNode(node23, null, node26);
		
		//System.out.println(of39.isBalanced(node21));
		System.out.println(of39.isBalanced2(node21).getIsBalanced());
		
		//功能测试
		 // 03.二叉树的所有节点都没有右子树
	    //                 1                     
	    //              /                             
	    //             2                             
	    //           /                                   
	    //          4  
		BinaryTreeNode node31 = new BinaryTreeNode(1);
		BinaryTreeNode node32 = new BinaryTreeNode(2);
		BinaryTreeNode node34 = new BinaryTreeNode(4);
		
		setBinaryTreeNode(node31, node32, null);
		setBinaryTreeNode(node32, node34, null);
		
		//System.out.println(of39.isBalanced(node31));
		System.out.println(of39.isBalanced2(node31).getIsBalanced());
		
		//功能测试
		 // 04.二叉树的所有节点都没有左子树
	    //                  1                      
	    //                      \                    
	    //                       3                 
	    //                         \           
	    //                         6
		BinaryTreeNode node41 = new BinaryTreeNode(1);
		BinaryTreeNode node43 = new BinaryTreeNode(3);
		BinaryTreeNode node46 = new BinaryTreeNode(6);
		
		setBinaryTreeNode(node41, null, node43);
		setBinaryTreeNode(node43, null, node46);
		
		//System.out.println(of39.isBalanced(node41));
		System.out.println(of39.isBalanced2(node41).getIsBalanced());
		
		//特殊输入测试
		 // 05.只有一个节点的二叉树
	    //                  1
		BinaryTreeNode node51 = new BinaryTreeNode(1);
		
		setBinaryTreeNode(node51, null, null);
		
		//System.out.println(of39.isBalanced(node51));
		System.out.println(of39.isBalanced2(node51).getIsBalanced());
		
		//特殊输入测试,6
		//指向二叉树的根节点的指针为NULL
		BinaryTreeNode node61 = null;
		//System.out.println(of39.isBalanced(node61));
		System.out.println(of39.isBalanced2(node61).getIsBalanced());
	}
}

运行结果(问题1:二叉树的深度):

4
3
3
1
0

运行结果(问题2:判断平衡二叉树

true
false
false
false
true
true

为什么新建一个reference类?

在上面的问题2的第二种解法代码中,我们使用后序遍历的方式遍历整颗二叉树。在遍历某结点的左右子结点之后,我们可以根据它的左右子结点的深度判断它是不是平衡的,并得到当前结点的深度。当遍历到根结点的时候,也就判断了整颗二叉树是不是平衡二叉树。由于要传递两个参数,一般的使用返回值的方法是行不通的,而且Java并不存在指针和简单数据类型的引用传值。一般的高级语言(如Python)会有元组这么一个概念(Java没有那就自己定义一个),既然只能返回一个值,那就返回一个复合类型的,函数改造完成~

我想说的是,每个入了门的程序员都知道参数是复制传值,在C/C++中只能用指针和引用的方式从参数列表中传递或获取值,在Java中,除了基本数据类型和String类型外,也是引用传值。但是基本数据类型传进函数体你改动了有什么意义?你只是改动了一个副本。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值