题目介绍
给你一棵二叉树的根节点,返回该树的 直径 。
二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。
两节点之间路径的 长度 由它们之间边数表示。


提示:
- 树中节点数目在范围
[1, 104]内 -100 <= Node.val <= 100
cpp
class Solution {
public:
int diameterOfBinaryTree(TreeNode* root) {
}
};
全文3600字,阅读+思考 15min ( 递归第二阶段核心之作
原题链接 : 543. 二叉树的直径 - 力扣(LeetCode)
解析
1 . 本题需求很明确:给你一棵二叉树 (仍是给一个root代表整棵二叉树),要求求出这棵树的直径。
2 . 根据示例1和示例2的解释,直径就是某个根节点,其左边能延申最远的长度 + 右边能延申最远的长度
3 . 就这么一个参数且只能看到当前树的根节点和左右节点,必然是要用递归------才能代表它们也可以代表一棵树
递归------分步解析
为何取这个"标题"------其实是博主第一次的思路,接下来诸位听我娓娓道来
1 . 读完题包括示例,解析出:既然要算某棵树的左右边分别能延申的最大长度,我脑中灵光一闪------这就是求解"二叉树的深度"。
故先设计出了第一个函数,求解当前树的最大深度
求深度曾是我们的解析重点,到如今已经成为解题趁手的工具------09 二叉树的最大深度-CSDN博客
cpp
class Solution {
public:
int _depth(TreeNode* root)
{
if(root == nullptr) return 0;
int leftd = _depth(root->left);
int rightd = _depth(root->right);
return leftd>rightd?leftd+1:rightd+1;
}
int diameterOfBinaryTree(TreeNode* root) {
}
};
注:
a . 当前树的最大深度:如果左边深一点取leftd+1,反之取右边rightd+1
2 . 思路回归正轨:递归,下一句 :老两样------核心任务 递归出口3 . 核心任务 :
在每个核心任务中,我是如此设计:既然要算出整棵树最大的直径,那就把每棵树的直径算出来,然后取最大。
而某棵树的直径 等于 以它为根(拐点)向左的深度 + 向右的深度,至于最大就要进行比较
4 . 于是我把核心任务一步一步完成,
a . 接下来是计算某棵树的直径
cpp
class Solution {
public:
// ...
int _diameterOfBinaryTree(TreeNode* root) {
if(root == nullptr) return 0;
int maxleft = _depth(root->left);
int maxright = _depth(root->right);
return maxleft+maxright;//计算当前树的直径 (左右子树的深度和)
}
int diameterOfBinaryTree(TreeNode* root) {
}
};
注:
_diameterOfBinaryTree里,取名就看得出:
maxleft 拿到当前树的左树最大深度
maxright 拿到当前树的右树最大深度
以当前树root为拐点,那么这棵树的直径我就算出来了 :maxleft+maxright
b. 然后在上层(给出的接口)调用_diameterOfBinaryTree,算出所有树的直径后,取最大
cpp
class Solution {
public:
// ...
int diameterOfBinaryTree(TreeNode* root) {
if(root == nullptr) return 0;
int left = diameterOfBinaryTree(root->left);
int right = diameterOfBinaryTree(root->right);
int cur = _diameterOfBinaryTree(root);
return max(max(left,right),cur);// 取出当前树最大的直径
}
};
注:
1 . 相信你也看出来了,我在上层调用下层的_diameter算出了当前树的直径,但为了算出整棵树方便比较取最大,又得递归调用算出左树 右树
2 . 最后比较------ 当前树直径 左树直径 右树直径 取最大;向上返回,或许这个结果是 left 也许是 right 又或许是最终的结果
3 . 其实diameterOfBinaryTree的核心任务:取出当前树最大直径
4 . 递归出口 :判断root是否为空 ,深度_depth里 ,返回为0 无深度
_diameter里,返回为0,表示无直径
diameter里,返回0,表示无最大直径
完整代码:
cpp
class Solution {
public:
int _depth(TreeNode* root)
{
if(root == nullptr) return 0;
int leftd = _depth(root->left);
int rightd = _depth(root->right);
return leftd>rightd?leftd+1:rightd+1;
}
int _diameterOfBinaryTree(TreeNode* root) {
if(root == nullptr) return 0;
int maxleft = _depth(root->left);
int maxright = _depth(root->right);
return maxleft+maxright;//计算当前树的直径 (左右子树的深度)
}
int diameterOfBinaryTree(TreeNode* root) {
if(root == nullptr) return 0;
int left = diameterOfBinaryTree(root->left);
int right = diameterOfBinaryTree(root->right);
int cur = _diameterOfBinaryTree(root);
return max(max(left,right),cur);// 计算当前树的最大直径
}
};
时间线收束:
1 . 之所以这段思路 称为 :"递归------分步解析"------
2 . diameterOfBinaryTree的核心任务 :计算当前树的最大直径
_diameterOfBinaryTree的核心任务:计算当前树的直径(左右深度和)
_depth的核心任务 :计算当前树的深度
递归------双任务
优化写法,请重点掌握 :思想 + 代码
1 . "递归------分步解析"里,思路清晰、结果正确,虽然递归节点重复,但是它是对的嘛。"不管黑猫白猫,能捉老鼠的就是好猫"
2 . 但是,我们追求进步。且这个方法学会了很爽。
1 . "递归------分步解析"的递归------核心任务 : 算出当前树的最大直径
递归出口 :root为空树,不存在最大直径
2 . 能否将 求解每棵树深度 和 计算每棵树的深度和结合一下?这是优化思路1
3 . 能否就递归整棵树一遍就能直接得到最大直径 ? 这是优化思路2
4 . 都能
5 . 引入一个输出型参数 ,用来记录当前获得的最大二叉树直径
cpp
int _depth(TreeNode* root,int& maxdiameter)
{
if(root == nullptr) return 0;
int leftd = _depth(root->left,maxdiameter);
int rightd = _depth(root->right,maxdiameter);
maxdiameter = max(leftd+rightd,maxdiameter);
return leftd>rightd?leftd+1:rightd+1;
}
注:
1 . maxdiameter :起点为 0 ;输出型参数:传入引用,它能一直实时更新和记录最大直径
2 . 当_depth获得了当前树的左边深度 和 右边深度,不妨给当前树一个机会:计算一下它的直径,是否能与maxdiameter媲美;若能,更新maxdiameter,若不能,也无妨
3 . 然后继续完成计算深度的任务
上层代码就如此调用:
cpp
int diameterOfBinaryTree(TreeNode* root) {
int maxdiameter = 0;
_depth(root,maxdiameter);
return maxdiameter;
}
完整代码:
cpp
class Solution {
public:
int _depth(TreeNode* root,int& maxdiameter)
{
if(root == nullptr) return 0;
int leftd = _depth(root->left,maxdiameter);
int rightd = _depth(root->right,maxdiameter);
maxdiameter = max(leftd+rightd,maxdiameter);
return leftd>rightd?leftd+1:rightd+1;
}
int diameterOfBinaryTree(TreeNode* root) {
int maxdiameter = 0;
_depth(root,maxdiameter);
return maxdiameter;
}
};
注:
1 . 双任务执行 :计算当前树的深度 ,maxdiameter平等与每棵树的直径一决高下
2 . 输出型参数的妙用,切记切记
总结以及完整参考代码

cpp
class Solution {
public:
int _depth(TreeNode* root)
{
if(root == nullptr) return 0;
int leftd = _depth(root->left);
int rightd = _depth(root->right);
return leftd>rightd?leftd+1:rightd+1;
}
int _diameterOfBinaryTree(TreeNode* root) {
if(root == nullptr) return 0;
int maxleft = _depth(root->left);
int maxright = _depth(root->right);
return maxleft+maxright;//计算当前树的直径 (左右子树的深度)
}
int diameterOfBinaryTree(TreeNode* root) {
if(root == nullptr) return 0;
int left = diameterOfBinaryTree(root->left);
int right = diameterOfBinaryTree(root->right);
int cur = _diameterOfBinaryTree(root);
return max(max(left,right),cur);// 计算当前树的最大直径
}
};
cpp
class Solution {
public:
int _depth(TreeNode* root,int& maxdiameter)
{
if(root == nullptr) return 0;
int leftd = _depth(root->left,maxdiameter);
int rightd = _depth(root->right,maxdiameter);
maxdiameter = max(leftd+rightd,maxdiameter);
return leftd>rightd?leftd+1:rightd+1;
}
int diameterOfBinaryTree(TreeNode* root) {
int maxdiameter = 0;
_depth(root,maxdiameter);
return maxdiameter;
}
};
如果不熟悉输出型参数,我们可以从这篇深度理解,这是二叉树阶段一核心之作:08 二叉树的中序遍历-CSDN博客