【LeetCode Hot100 刷题日记 (37/100)】104. 二叉树的最大深度 —— 深度优先搜索(DFS)与广度优先搜索(BFS)🌳

33 阅读5分钟

📌 题目链接:104. 二叉树的最大深度 - 力扣(LeetCode)

🔍 难度:简单 | 🏷️ 标签:树、深度优先搜索(DFS)、广度优先搜索(BFS)、递归

⏱️ 目标时间复杂度:O(n)

💾 空间复杂度:DFS: O(height),BFS: O(n)


题目分析

给定一个二叉树的根节点 root,要求返回其最大深度

📘 定义:二叉树的“最大深度”是从根节点到最远叶子节点的最长路径上的节点数(注意是“节点数”,不是边数!)。

例如:

  • 示例1:[3,9,20,null,null,15,7] → 最大深度为 3(路径:3 → 20 → 15 或 7)
  • 示例2:[1,null,2] → 最大深度为 2(路径:1 → 2)

💡 关键点

  • 空树深度为 0;
  • 叶子节点是指左右子树都为空的节点;
  • 本题本质是遍历整棵树,并记录从根到叶的最长路径长度。

核心算法及代码讲解

本题有两种经典解法:深度优先搜索(DFS)广度优先搜索(BFS)。两者在面试中都高频出现,务必掌握!

✅ 方法一:深度优先搜索(DFS)—— 递归实现(推荐!)

🧠 核心思想
一棵二叉树的最大深度 = max(左子树最大深度, 右子树最大深度) + 1
这是典型的分治 + 递归思想:将大问题分解为两个相同结构的子问题。

📌 递归三要素:

  1. 终止条件:当前节点为 nullptr,返回 0;
  2. 递归关系maxDepth(root) = max(maxDepth(left), maxDepth(right)) + 1
  3. 返回值:当前子树的最大深度。

🧪 时间 & 空间复杂度:

  • 时间复杂度:O(n) —— 每个节点访问一次;
  • 空间复杂度:O(height) —— 递归栈深度等于树的高度(最坏 O(n),平衡树 O(log n))。

💻 C++ 代码(带行注释):

class Solution {
public:
    int maxDepth(TreeNode* root) {
        // 🛑 终止条件:空节点深度为 0
        if (root == nullptr) return 0;
        // 🔁 递归计算左右子树深度
        int leftDepth = maxDepth(root->left);
        int rightDepth = maxDepth(root->right);
        // ✅ 当前节点深度 = 左右子树最大深度 + 1
        return max(leftDepth, rightDepth) + 1;
    }
};

💡 面试加分点

  • 能说出这是“后序遍历”(先处理子树,再处理根);
  • 能对比迭代 vs 递归的优劣;
  • 能指出该写法简洁、易理解,是面试首选。

✅ 方法二:广度优先搜索(BFS)—— 层序遍历(队列实现)

🧠 核心思想
按层遍历树,每遍历完一层,深度 +1。
使用队列存储当前层所有节点,每次处理整层后再进入下一层。

📌 关键技巧:

  • queue.size() 获取当前层节点数量;
  • 内层 while 循环一次性处理完当前层所有节点;
  • 每完成一层,ans++

🧪 时间 & 空间复杂度:

  • 时间复杂度:O(n) —— 每个节点入队出队一次;
  • 空间复杂度:O(n) —— 队列最坏情况(完全二叉树最后一层)存储 n/2 个节点。

💻 C++ 代码(带行注释):

class Solution {
public:
    int maxDepth(TreeNode* root) {
        if (root == nullptr) return 0;
        queue<TreeNode*> Q;
        Q.push(root);
        int ans = 0; // 📏 记录层数(即深度)
        while (!Q.empty()) {
            int sz = Q.size(); // 🎯 当前层的节点数
            while (sz-- > 0) { // 👉 一次性处理整层
                TreeNode* node = Q.front();
                Q.pop();
                if (node->left) Q.push(node->left);
                if (node->right) Q.push(node->right);
            }
            ans++; // 📈 完成一层,深度 +1
        }
        return ans;
    }
};

💡 面试加分点

  • 能解释 BFS 为什么能求深度(因为按层扩展);
  • 能说出 BFS 更适合“找最短路径”类问题(如最小深度);
  • 能对比 DFS/BFS 在内存使用上的差异(DFS 用栈,BFS 用队列)。

解题思路(分步骤)

🚶‍♂️ DFS 思路步骤:

  1. 判断边界:若根为空,直接返回 0;
  2. 递归左子树,得到左子树最大深度;
  3. 递归右子树,得到右子树最大深度;
  4. 取较大值 +1,作为当前树的深度;
  5. 返回结果

🚶‍♀️ BFS 思路步骤:

  1. 初始化队列,将根节点入队;
  2. 初始化深度计数器 ans = 0
  3. 当队列非空时循环
    • 获取当前队列大小(即当前层节点数);
    • 循环弹出这些节点,并将其非空子节点入队;
    • 本层处理完毕,ans++
  4. 返回 ans

算法分析

方法时间复杂度空间复杂度适用场景面试推荐度
DFS(递归)O(n)O(height)通用、简洁⭐⭐⭐⭐⭐
BFS(队列)O(n)O(n)需要按层处理⭐⭐⭐⭐

📌 重要提醒

  • DFS 更省空间(尤其对平衡树);
  • BFS 更直观体现“深度 = 层数”;
  • 若题目改为“最小深度”,BFS 可提前终止,效率更高!

代码

✅ C++ 完整代码(保留模板,含测试)

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

// Definition for a binary tree node.
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};

class Solution {
public:
    // 方法一:DFS(递归)
    int maxDepth(TreeNode* root) {
        if (root == nullptr) return 0;
        return max(maxDepth(root->left), maxDepth(root->right)) + 1;
    }

    // 方法二:BFS(层序遍历)
    // int maxDepth(TreeNode* root) {
    //     if (root == nullptr) return 0;
    //     queue<TreeNode*> Q;
    //     Q.push(root);
    //     int ans = 0;
    //     while (!Q.empty()) {
    //         int sz = Q.size();
    //         while (sz-- > 0) {
    //             TreeNode* node = Q.front(); Q.pop();
    //             if (node->left) Q.push(node->left);
    //             if (node->right) Q.push(node->right);
    //         }
    //         ans++;
    //     }
    //     return ans;
    // }
};

// 测试
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    // 构建示例1: [3,9,20,null,null,15,7]
    TreeNode* root = new TreeNode(3);
    root->left = new TreeNode(9);
    root->right = new TreeNode(20);
    root->right->left = new TreeNode(15);
    root->right->right = new TreeNode(7);

    Solution sol;
    cout << "Max Depth: " << sol.maxDepth(root) << "\n"; // 输出: 3

    // 示例2: [1,null,2]
    TreeNode* root2 = new TreeNode(1);
    root2->right = new TreeNode(2);
    cout << "Max Depth: " << sol.maxDepth(root2) << "\n"; // 输出: 2

    return 0;
}

✅ JavaScript 完整代码

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */

/**
 * @param {TreeNode} root
 * @return {number}
 */
var maxDepth = function(root) {
    // DFS 递归解法
    if (root === null) return 0;
    const leftDepth = maxDepth(root.left);
    const rightDepth = maxDepth(root.right);
    return Math.max(leftDepth, rightDepth) + 1;
};

// BFS 解法(可选)
// var maxDepth = function(root) {
//     if (root === null) return 0;
//     const queue = [root];
//     let depth = 0;
//     while (queue.length > 0) {
//         let size = queue.length;
//         while (size-- > 0) {
//             const node = queue.shift();
//             if (node.left) queue.push(node.left);
//             if (node.right) queue.push(node.right);
//         }
//         depth++;
//     }
//     return depth;
// };

// 测试用例
// 构建树略(LeetCode 环境自动处理)

🌟 本期完结,下期见!🔥

👉 点赞收藏加关注,新文更新不迷路。关注专栏【算法】LeetCode Hot100刷题日记,持续为你拆解每一道热题的底层逻辑与面试技巧!

💬 欢迎留言交流你的解法或疑问!一起进步,冲向 Offer!💪

📌 记住:当你在刷题时,不要只看答案,要像写这篇文章一样,深入思考每一步背后的原理、优化空间和面试价值。这才是真正提升算法能力的方式!