题目:从二叉树的节点A出发,可以向上或者向下走,但沿途的节点只能经过一次,当到达节点B时,路径上的节点数叫作A到B的距离。对于给定的一棵二叉树,求整棵树上节点间的最大距离。给定一个二叉树的头结点root,请返回最大距离。保证点数大于等于2小于等于500.
思路:理解题目的含义,对于一棵以root为根的二叉树,树上的最大距离可能来自3中情况:
情况1:完全来自root的左子树,如图所示,即最大路径不经过root结点,只在结点1的左子树2上面,此时的最大距离为8。
情况2:完全来自root结点的右子树,如图所示,最大路径不经过root结点,只在结点1的右侧左子树3上面,此时最大距离是9。
情况3:来自结点root的两侧,如图所示,经过root结点,此时的最大距离=root的左子树的高度(即结点3的最长路径)+root右子树的高度(即结点3的最长路径)+root结点本身。
分析可知,要计算结点root所在子树的最长距离,需要已知:左子树②的最长距离LMaxLength,左子树的高度LHeight;右子树③的最长距离RMaxLength,右子树的高度RHeight.然后比较Math.max(LMax,RMax,(LHeight+RHeight+1)),其最大值就是这棵二叉树的最大距离,即对于每个子树,需要求出它的最大距离和最大高度。显然这就是一个递推关系式,可以使用递归来实现,即设计一个递归函数,给定一个根结点root,求出这个根结点的最大距离max和最大高度height并返回这2个数值。其中maxLength= Math.max(LMax,RMax,(LHeight+RHeight+1));而由于要返回这棵子树的高度,如何求子树的高度呢?二叉树的高度就是它的2个子树高度中的较大值再加上1,即height=Math.max(LHeight, RHeight)+1;
递归的递推关系有了,关键是找到递归的起始条件或者理解为终止条件。这里使用的思想是后序遍历(先遍历左右子树再处理结论),联系二叉树的后序遍历算法,进行改编。显然if(root==null)时:max=0;height=0;
总结:设计一个递归函数,输入根结点root,求出这棵二叉树的最大距离maxLength和高度length并返回。递推关系为:
maxLength= Math.max(LMax,RMax,(LHeight+RHeight+1));
height=Math.max(LHeight, RHeight)+1
边界条件为:
if(root==null) return max=0;height=0;
在Java中不能分开返回2个值,因此要将2个值整合成为一个数组进行返回即可。
importjava.util.*;
//求二叉树上结点的最大距离:递归;最大值只可能来自3中情况
publicclass LongestDistance {
public int findLongest(TreeNode root) {
//特殊输入
if(root==null) return 0;
//调用递归函数来求得最大距离maxLength和高度height
int[] results=this.process(root);
//返回结果
return results[0];
}
//这是一个递归方法,用于求出一个二叉树的最大距离和高度并返回这2个值
private int[] process(TreeNode root){
int[] tempResults=new int[2];
//边界条件
if(root==null){
tempResults[0]=0;
tempResults[1]=0;
return tempResults;
}
//最大值来自3中情况,进行比较
//左子树的结果:
int[]paramLeft=this.process(root.left);
int LMaxLength=paramLeft[0];
int LHeight=paramLeft[1];
//右子树的结果:
int[] paramRight=this.process(root.right);
int RMaxLength=paramRight[0];
int RHeight=paramRight[1];
//比较得到最大值和高度,并组成数组返回,常识:Math.max()函数只能比较2个数的大小
//递归的递推关系
tempResults[0]=Math.max(Math.max(LMaxLength,RMaxLength),LHeight+RHeight+1);
tempResults[1]=Math.max(LHeight,RHeight)+1;
//带有返回值的递归函数
return tempResults;
}
}
常识:Math.max()函数只能放入2个参数,即只能比较2个数的大小,如果需要比较更多数的大小,那么在Math.max()里面再套用Math.max()即可。
对于递归方法,可以有返回值也可以没有返回值,并不影响递归的使用,递归的设计应该从功能上来思考,思考这个递归方法需要解决一个什么问题?需要输入的信息是什么?返回的信息又是什么?在这个递归方法中需要对下一层递归方法的返回值进行怎样的处理?(即如何递推);从策略上来讲,就是先明确递推关系再明确初始条件(终止条件)。