[算法系列]递归应用——二叉树(2):一种带信息递归返回的求解方式
本文是递归系列文的第七篇,和上篇文章类似,介绍BinaryTree的解题思路。这里介绍一种和“遍历”行为类似的,自下而上递归返回信息的解题思路。其规则的写法、并不复杂的思路,可解决大多bintree中与子树有关的问题(但愿吧哈哈哈)
0.引子:求二叉树节点中的最大值和最小值
此题当然可以通过遍历整棵二叉树,将遍历途中遇到的最大值和最小值进行保存。遍历完成后maxVal和minVla即为所求:
class MaxAndMinInBinTree{
int maxVal = Integer.MIN_VALUE;
int minVal = Integer.MAX_VALUE;
public int[] getMinMaxInBT(TreeNode node){
process(node);
return new int[]{
maxVal, minVal};
}
public void process(TreeNode node){
if(node == null) return;
maxVal = Math.max(node.val , maxVal);
minVal = Math.min(node.val, minVal);
process(node.left);
process(node.right);
}
}
那么这道题目除了用 二叉树的 ”遍历“ 思路,还可以怎么想呢?
回忆我们求二叉树的高度时用到的思路:
当前子树的高度 =max( 左子树的高度 ,右子树高度)+ 1
- 在递归中逐渐返回到头结点:
树的高度 = max(根的子树高度,根的右子树高度) +1
这其实就是一种和遍历思路稍显区别的,俺将其命名为带信息返回的求解思路。那么如果将其运用到求整棵树的最大最小值时,就可以自然而然地有如下想法:
当前子树的最大值 = max(左子树最大值,右子树最大值,当前节点的值)
当前子树的最小值 = min(左子树最小值,右子树最小值,当前节点的值)
- 在递归中逐渐向上返回到根节点。
该思路其一般可写成如下框架:
public ReturnData process(TreeNode node){
if(node == null){
//处理节点为空的情况,也是”递“到达的最深处,”归“上去的起点
}
ReturnData leftDate = process(node.left);
ReturnData rightData = process(node.right);
return new ReturnData(
//根据当前节点考虑可能性,构造当前要向上返回的信息集
)
}
下面来解释一波上述的伪代码:
-
ReturnData是自定义的一个类,里面包含的是递归过程中每次需要返回的所有信息
-
看整个process函数框架,看过我前面详解递归的小伙伴应该比较清楚:node == null 实际上就是边界条件,是递归的出口,在此处我们需要拿捏最小问题的处理方式。
紧接着,是两个递归调用process的过程,用leftData和rightData去接收左子树和右子树的结果。这一点前面也提到过:该模式下process函数会一口气走到最左下的为null的节点,然后再返回到右下,从叶节点开始,逐渐往上地返回。
在返回过程中,构建了一个新的ReturnData实例对象。这也就把所需要返回的信息向上地”归“到了根节点。
-
在新构建返回信息的实例对象中,就是我们根据可能性进行构造的过程。
好了,现在看看用这个方法时怎样操作的:
class MaxAndMinInBinTree2{
/* 这个题的返回信息就是所要求的最大值,最小值 */
public static class ReturnData{
public int maxVal;
public int minVal;
public ReturnData(int maxVal , int minVal){
this.maxVal = maxVal;
this.minVal = minVal;
}
}
public void getMinMax(TreeNode node){
ReturnData data = process(node);
System.out.println(data.maxVal + " " + data.minVal);
}
private ReturnData process(TreeNode head){
/* 递归边界条件,构造最初的返回信息 */ */
if(head == null){
return new ReturnData(Integer.MIN_VALUE