一、二叉树的自顶向下递归
自顶向下(top-down)
-
和前序遍历紧密关联(根->左->右)
-
当前节点的情况依赖于其父节点的情况
-
考虑完父节点,再考虑当前节点
-
适用于该节点左右子节点无依赖的情况,或必须要考虑根结点或父节点的情况
二、二叉树的自底向上递归
自底向上(bottom-up)
-
和后序遍历紧密关联(左->右->根)
-
当前节点的情况依赖于其所有子节点的情况
-
考虑完所有子节点,再考虑当前节点
-
适用于左右子节点有依赖的情况,或某些情况下无法考虑根结点或父节点的情况
三、对应习题
Leetcode104 二叉树最大深度
class Solution {
public int maxDepth(TreeNode root) {
// 如果 root 为空,直接返回 0
if(root == null) return 0;
// 递归调用 maxDepth,求出当前节点的左子树的最大深度
int left = maxDepth(root.left);
// 递归调用 maxDepth,求出当前节点的右子树的最大深度
int right = maxDepth(root.right);
// 求出当前节点的左右子树中较大的值
int childMaxDepth = Math.max(left,right);
// 二叉树的最大深度就是它的左右子树中较大的值加上 1
return childMaxDepth + 1;
}
}
这道题用自顶向下或自底向上都可以解答,因为既符合要考虑父节点情况,也符合左右节点有依赖的情况,本答案为自底向上。
Leetcode111 二叉树的最小深度
class Solution {
public int minDepth(TreeNode root) {
// 边界情况处理
if (root == null) return 0;
// 设置一个队列,用来存储二叉树中的元素
Queue<TreeNode> nodeQueue = new LinkedList<>();
// 队列添加二叉树的根节点
nodeQueue.add(root);
// 设置 depth 用来保存输出结果
int depth = 0;
// 遍历队列,直到队列为空,说明访问了二叉树中所有的节点
while (!nodeQueue.isEmpty()) {
// 用来记录 queue 的长度,即每层节点的个数
int size = nodeQueue.size();
// 每到一层,深度就 +1
depth++;
// 使用 for 循环,将 nodeQueue 中的元素统计
for (int i = 0; i < size; i++) {
// 从 queue 中取出一个节点,此时,nodeQueue 已经抛出了这个节点
TreeNode curNode = nodeQueue.poll();
// curNode.left == null && curNode.right == null
// 说明是叶子结点
// 由于【最小深度是从根节点到最近叶子节点的最短路径上的节点数量】
// 直接返回 depth
if(curNode.left == null && curNode.right == null){
return depth;
}
// 判断当前节点的左子节点是否有值,如果有,则添加到 nodeQueue 中
if (curNode.left != null){
nodeQueue.add(curNode.left);
}
// 判断当前节点的右子节点是否有值,如果有,则添加到 nodeQueue 中
if (curNode.right != null){
nodeQueue.add(curNode.right);
}
}
}
// 返回 depth
return depth;
}
}
这道题只能用自顶向下的解法,因为要找最小深度,必须是从根节点到叶子结点的路径,然后比较高度,取高度的最小值。