12 . 二叉树的直径

题目介绍

给你一棵二叉树的根节点,返回该树的 直径

二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 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;
    }
};

求深度:09 二叉树的最大深度-CSDN博客

如果不熟悉输出型参数,我们可以从这篇深度理解,这是二叉树阶段一核心之作:08 二叉树的中序遍历-CSDN博客

相关推荐
智者知已应修善业2 小时前
【51单片机2个按键控制流水灯运行与暂停】2023-9-6
c++·经验分享·笔记·算法·51单片机
Halo_tjn2 小时前
Java Set集合相关知识点
java·开发语言·算法
生成论实验室3 小时前
《事件关系阴阳博弈动力学:识势应势之道》第四篇:降U动力学——认知确定度的自驱演化
人工智能·科技·神经网络·算法·架构
AI科技星3 小时前
全域数学·72分册:场计算机卷【乖乖数学】
算法·机器学习·数学建模·数据挖掘·量子计算
科研前沿4 小时前
镜像孪生VS视频孪生核心技术产品核心优势
大数据·人工智能·算法·重构·空间计算
水蓝烟雨4 小时前
1931. 用三种不同颜色为网格涂色
算法·leetcode
晨曦夜月4 小时前
map与unordered_map区别
算法·哈希算法
qeen874 小时前
【数据结构】建堆的时间复杂度讨论与TOP-K问题
c语言·数据结构·c++·学习·
图码5 小时前
如何用多种方法判断字符串是否为回文?
开发语言·数据结构·c++·算法·阿里云·线性回归·数字雕刻
handler015 小时前
Linux 内核剖析:进程优先级、上下文切换与 O(1) 调度算法
linux·运维·c语言·开发语言·c++·笔记·算法