二叉树的直径 | 刷题打卡

99 阅读2分钟

本文正在参与掘金团队号上线活动,点击 查看大厂春招职位

一、题目描述:

今天带来的题目是和上次介绍过的题目最长同值路径|刷题打卡有着同样思路的题目,希望大家能借此来加理解。

题目很直接明了,求一颗二叉树的直径,所谓直径指的是两个节点之间路径长度中的最大值,而路径指的是两个节点之间边的数量。

image.png

二、思路分析:

遇到树的题目,直接递归返回就完事了,今天要介绍的这种类型,最终的结果不一定是经过根节点的,所以需要在递归遍历的时候使用中间变量比较一下。

递归

  • 我们还是从最底层的叶子节点开始往上考虑,考虑每个节点能够提供给父节点的收益是多少。(这里的收益有点求二叉树的高度的递归函数返回那意思)
  • 对于每个叶子节点,因为其左右孩子都是NULL,相当于提供的收益都是0,所以叶子节点能提供给父节点的收益就是1。因为这题目同样要求的是路径,路径是不能分叉的。所以在递归函数里返回一个长度较长的子树带来的收益,同时加上root节点本身的收益1,即: 1 + max($left, $right);

image.png

  • 注意,上图中的最大路径直径是不经过root节点的。此时以左边数字2为根的子树产生了最大直径,所以在递归过程中我们需要使用一个全局变量来跟这种情况可能产生的路径长度做比较,这种情况的路径长度就是:当前遍历到的root加上左右子树产生的收益 1 + $right + $left

  • 注意我这求得结果相当于是路径上的节点数,所以最后的结果需要减1哦

  • 时间复杂度:O(N),这里 N 二叉树中节点的个数。

  • 空间复杂度:O(H),H是二叉树的高度。

三、AC 代码:

/**
 * Definition for a binary tree node.
 * class TreeNode {
 *     public $val = null;
 *     public $left = null;
 *     public $right = null;
 *     function __construct($val = 0, $left = null, $right = null) {
 *         $this->val = $val;
 *         $this->left = $left;
 *         $this->right = $right;
 *     }
 * }
 */
class Solution {

    /**
     * @param TreeNode $root
     * @return Integer
     */
    protected $max = 0;
    function diameterOfBinaryTree($root) {
        $this->helpMe($root);
        return $this->max - 1;
    }

    protected function helpMe($root) {
        if ($root == null) {
            return 0;
        }

        $left = $this->helpMe($root->left);
        $right = $this->helpMe($root->right);

        $this->max = max($this->max, $left + $right + 1);

        return max($left, $right) + 1;
    }
}

四、总结:

依稀记得这道题当初实习面试字节的时候被问到过,当时啥都不会,哈哈哈。 遇到二叉树的问题直接考虑递归。不过今天这种类型的题目递归函数的返回并不一定是最终要求的结果,因为路径这个可能不经过root节点。所以需要在遍历的过程中比较一下可能产生的最大值情况。类似的题目还有几道,下次我们再见。