【二叉树专题】一道深入浅出的 DFS 题:求二叉树的直径(含通俗易懂讲解)
题目: 给你一棵二叉树的根节点,返回这棵树的 直径。
直径 是任意两个节点路径中,最长的一条路径所经过的边数。
比如下面这棵树:
1/ \2 3/ \ 4 5
它的最长路径是:4 → 2 → 5
或者 4 → 2 → 1 → 3
,路径长度都是 3(注意是边数而不是节点数),所以直径就是 3。
解题思路:每个节点都可能是“最长路径”的中心
我们要做的,是找到一条从一个节点出发,向下穿过某个节点走到另一个节点的路径,这条路径的长度最长。
换句话说:
-
每个节点都可能是“最长路径”的中间节点
-
这个路径的长度 = 它左子树的最大深度 + 右子树的最大深度
所以我们可以:
-
对每个节点进行深度优先搜索(DFS)
-
每个节点返回它的最大深度
-
同时,在回溯时顺便更新一个全局变量,记录最长路径
代码实现(Java)
class Solution {int ans = 0;public int diameterOfBinaryTree(TreeNode root) {dfs(root);return ans;}int dfs(TreeNode u) {if (u == null) return 0;int l = dfs(u.left); // 左子树深度int r = dfs(u.right); // 右子树深度ans = Math.max(ans, l + r); // 更新最大直径(路径长度)return Math.max(l, r) + 1; // 返回当前节点的深度}
}
每行代码都讲清楚!
全局变量 ans
int ans = 0;
用于记录当前找到的最大直径(最长路径的边数)。
主函数:diameterOfBinaryTree
public int diameterOfBinaryTree(TreeNode root) {dfs(root);return ans;
}
-
从根节点开始递归
-
所有更新都在
dfs
过程中完成,最终返回最大值即可
DFS 函数:
int dfs(TreeNode u) {if (u == null) return 0;
-
如果是空节点,深度为 0,直接返回
int l = dfs(u.left), r = dfs(u.right);
-
分别获取左右子树的最大深度
ans = Math.max(ans, l + r);
-
当前节点的最长路径:左子树深度 + 右子树深度
-
更新
ans
,记录目前为止最长的路径
return Math.max(l, r) + 1;
-
当前节点的深度:左右子树较大者 + 1(加上当前这一层)
-
这个值会被传给父节点,用于计算直径
举个例子帮助理解
我们用这棵树来举例:
1/ \2 3/ \ 4 5
-
节点 4 和 5 的深度是 1
-
节点 2 的左右子树深度为 1+1 = 2,更新直径为 2
-
节点 3 的深度是 1
-
节点 1 的左右深度为 2 和 1,路径长度为 3,更新直径为 3
所以最后的直径为 3。
时间与空间复杂度分析
-
时间复杂度:O(n)
每个节点都只被访问一次,n 是节点数。 -
空间复杂度:O(h)
h 是树的高度。递归调用栈最多会达到 h 层。
总结一句话记住:
每个节点都可以是“最长路径”的中心,左边能走多远 + 右边能走多远,就是它能提供的最长路径!
通过 DFS 遍历整棵树,记录所有节点作为“中心”时的最长路径长度,找出最大的那一个,就是二叉树的直径。