<LeetCode>二叉树的直径

题目如下:
在这里插入图片描述
这道题需要注意的一点是:二叉树的直径(即最长路径),不一定经过根结点。下图就是不经过根结点的例子(图中黑色的结点表示最长路径的起讫点):
在这里插入图片描述

解题思路:子问题定义

二叉树的解题技巧是,首先判断问题能否划分为子问题、应当划分为什么样的子问题。二叉树直径实际上就是二叉树中的最长路径,我们是可以划分出子问题的:

二叉树的最长路径 = \max { 左子树的最长路径, 右子树的最长路径, 经过根结点的最长路径 }
二叉树的最长路径=max{左子树的最长路径,右子树的最长路径,经过根结点的最长路径}

其中左子树的最长路径和右子树的最长路径是两个可以递归求解的子问题,那么经过根结点的最长路径如何计算呢?是左子树的深度加上右子树的深度。代入上面的式子得到:

二叉树的最长路径 = \max { 左子树的最长路径, 右子树的最长路径, 左子树的深度 + 右子树的深度 }
二叉树的最长路径=max{左子树的最长路径,右子树的最长路径,左子树的深度+右子树的深度}

等等。这里好像出现了两个子问题:子树的最大直径、子树的最大深度。这难道是要把树遍历两遍吗?非也,我们只需要让遍历函数返回两个值即可。

Python 通过 tuple 类型很好地支持了函数的多返回值。让我们先写一版 Python 的代码:

# 返回二元 tuple (depth, diameter)
# depth 表示子树的最大深度,diameter 表示子树的最长路径(直径)
def traverse(root):
    if root is None:
        return (0, 0)

    left_depth, left_diam = traverse(root.left)
    right_depth, right_diam = traverse(root.right)
    # 求二叉树深度的常规方法
    depth = 1 + max(left_depth, right_depth)
    # 套用上面推导出的最长路径公式
    diam = max(left_diam, right_diam, left_depth + right_depth)
    return depth, diam

def diameterOfBinaryTree(root):
    depth, diam = traverse(root)
    return diam


可以看到 Python 代码写起来还是听方便的。但是很多小伙伴是用 C++ 和 Java 写算法题的,这时候就比较麻烦了。这时候就要用到另一个技巧:在二叉树遍历中使用全局变量。

二叉树遍历中的全局变量

乍一看来,我们的遍历函数必须返回两个值。如果我们把返回两个值的函数拆成两个函数,会出现重复递归,拖慢算法的执行时间。但仔细一看代码,似乎发现了点什么:

如果我们看函数返回的第二个值,也就是子树的直径(最长路径),我们会发现,我们所做的,不过是递归计算左右子树的最长路径,然后再通过这个计算出当前树的最长路径。既然我们始终都是在求它的最大值,那么用一个全局变量保存它的最大值不就可以了?

Amazing!也就是说,我们把最大直径放在函数返回值里,是让其中的某个最大值一层一层地返回上去,直到 DFS 的起点。而使用全局变量的话,则是让最大值可以直接抵达终点。

这样,我们的函数就可以只返回一个变量了。

int diameter;

public int diameterOfBinaryTree(TreeNode root) {
    diameter = 0;
    traverse(root);
    return diameter;
}

// 返回树的深度
int traverse(TreeNode root) {
    if (root == null) {
        return 0;
    }

    int left = traverse(root.left); // 左子树的深度
    int right = traverse(root.right); // 右子树的深度
    // 直接访问全局变量
    diameter = Math.max(diameter, left + right);
    return 1 + Math.max(left, right);
}

拓展:全局变量方法的原理与更多应用

在这道题中,全局变量计算的是路径的最大值(max)。计算 max 的方式不是一次性求出来的,而是在二叉树遍历的过程中,每出现一个值,就把这个值和全局变量比较计算,算一个最大值。最终全局变量能得到全局的最大值。

实际上这利用了 max 的性质,max 是一种在线算法。简单来说,在线算法就是在计算的时候,所有的输入数据以“流”的形式一个个进来,算法每次只处理一条数据,不需要保存全部的数据。

除了 max 之外,sum、all 也都属于在线算法(all 指的是 x1 && x2 && … && xn 这样的计算)。可以举几个其他的二叉树题目例子:

二叉树的坡度:563. Binary Tree Tilt(sum)
判断平衡二叉树:110. Balanced Binary Tree(all)
二叉树路径数字:129. Sum Root to Leaf Numbers(sum)

转载处:
作者:nettee
链接:https://leetcode-cn.com/problems/diameter-of-binary-tree/solution/liang-chong-si-lu-shi-yong-quan-ju-bian-liang-yu-b/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以使用以下方法对二维向量vector<vector<int>>进行排序: 1. 使用STL中的sort函数进行排序。引用中提到了一些排序算法,比如堆排序(heap_sort),希尔排序(shell_sort),选择排序(select_sort)和快速排序(quick_sort_swap)。你可以根据需要选择其中一个算法对vector<vector<int>>进行排序。 2. 如果你想在创建二维向量时就进行排序,你可以使用引用中的方法通过vector创建二维数组,并在创建时对其中的元素进行排序。 3. 如果你已经创建了一个二维向量,你可以使用引用中的方法使用resize函数对二维向量进行重新分配,并在重新分配时对其中的元素进行排序。 无论你选择哪种方法,都可以对二维向量vector<vector<int>>进行排序。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [vectorstring和vectorint](https://blog.csdn.net/toCVer/article/details/122484732)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [leetcode2sumc-Code-Storm2019:力密码2019](https://download.csdn.net/download/weixin_38700430/19937142)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值