📌 题目链接: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。
这是典型的分治 + 递归思想:将大问题分解为两个相同结构的子问题。
📌 递归三要素:
- 终止条件:当前节点为
nullptr,返回 0; - 递归关系:
maxDepth(root) = max(maxDepth(left), maxDepth(right)) + 1; - 返回值:当前子树的最大深度。
🧪 时间 & 空间复杂度:
- 时间复杂度: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 思路步骤:
- 判断边界:若根为空,直接返回 0;
- 递归左子树,得到左子树最大深度;
- 递归右子树,得到右子树最大深度;
- 取较大值 +1,作为当前树的深度;
- 返回结果。
🚶♀️ BFS 思路步骤:
- 初始化队列,将根节点入队;
- 初始化深度计数器
ans = 0; - 当队列非空时循环:
- 获取当前队列大小(即当前层节点数);
- 循环弹出这些节点,并将其非空子节点入队;
- 本层处理完毕,
ans++;
- 返回
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!💪
📌 记住:当你在刷题时,不要只看答案,要像写这篇文章一样,深入思考每一步背后的原理、优化空间和面试价值。这才是真正提升算法能力的方式!