LeetCode 热题 100 | 二叉树(终)

目录

[1 二叉树小结](#1 二叉树小结)

[1.1 模式一](#1.1 模式一)

[1.2 模式二](#1.2 模式二)

[2 236. 二叉树的最近公共祖先](#2 236. 二叉树的最近公共祖先)

[3 124. 二叉树中的最大路径和](#3 124. 二叉树中的最大路径和)


菜鸟做题(返校版),语言是 C++

1 二叉树小结

菜鸟碎碎念

通过对二叉树的练习,我对 "递归" 有了一些肤浅的理解。我发现 "递归" 并不就等价于,先从上往下找到叶节点,再从下往上一直处理到根节点。它其实存在着两种模式。

1.1 模式一
  • 从上到下处理
  • 先处理根节点,后处理左右子树

代码一般都长这样:

cpp 复制代码
function(Treenode * root) {
    if (!root) return;

    root->val...
    function(root->left);
    function(root->left);
    ...
}

比如 437 题中要算前缀和,那么我们自然想到要从上到下进行累加,因此选择模式一。

1.2 模式二
  • 从下到上处理
  • 先处理左右子树,后处理根节点

代码一般都长这样:

cpp 复制代码
function(Treenode * root) {
    if (!root) return;

    function(root->left);
    function(root->right);
    root->val...
    ...
}

比如 236 题要找公共祖先,那么我们自然想到要从下往上找,因此选择模式二。

2 236. 二叉树的最近公共祖先

解题思路:

  • 判断当前节点的左右子树是否存在 p 或 q
  • 一旦当前节点的左右子树各自包含了 p 或 q
  • 那么当前节点为最近公共祖先

详细代码:

① 判断左右子树中是否存在 p 或 q,若有则 lson、rson 会为 true:

cpp 复制代码
bool lson = helper(root->left, p, q);
bool rson = helper(root->right, p, q);

相应的返回值如下:

cpp 复制代码
return lson || rson || (root == p || root == q);

意思是,对于某个子树的根节点,如果它的左右子树包含 p 或 q,或者它本身就是 p 或 q,那么等价于这个子树包含 p 或 q 。比如:对于浅绿色子树,根节点 "5" 的右子树(深绿色)包含 q,那么也等价于浅绿色子树包含 q 。

② 判断当前节点是否为最近公共祖先:

cpp 复制代码
if ((lson && rson) || ((root == p || root  == q) && (lson || rson))) {
    ans = root;
} 

这一行代码非常 tricky,((root == p || root == q) && (lson || rson)) 是啥意思?它的意思是,root 等于 p 或者 q,左子树或右子树找到 p 或者 q,只要这两个条件同时成立,那么当前节点 root 就是最近公共祖先。

为什么这个判断条件没有要求指明 root 和 lson、rson 分别找到的是 p 还是 q 呢?因为只要一方确定了,另一方自然就确定了。比如:如果 root 等于 p,那么 lson 或者 rson 之前找到的一定是 q 而不是 p,否则就矛盾了。

cpp 复制代码
class Solution {
public:

    TreeNode * ans;
    bool helper(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (!root) return false;

        bool lson = helper(root->left, p, q);
        bool rson = helper(root->right, p, q);
        if ((lson && rson) || ((root == p || root  == q) && (lson || rson))) {
            ans = root;
        } 
        return lson || rson || (root == p || root == q);
    }

    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        helper(root, p, q);
        return ans;
    }
};

3 124. 二叉树中的最大路径和

解题思路:

  • 从下向上遍历二叉树
  • 路径和 = 根节点 + 根节点的左子树 + 根节点的右子树
  • 根节点向父节点推荐自己

这里说的根节点泛指每个子树的根节点;"根节点的左子树" 具体是指从左子树中找出的最大路径和,后文所提到的 "左子树" 也是这个意思。

思路说明图:

针对根节点 "20","20" 的左子树("15")和右子树("7")会向 "20" 自荐,只要它们不拖后腿(路径和为负),那么 "20" + 它的左子树 + 它的右子树 的路径和就是最大的。接着,"20" 会选择左子树和右子树中的较大者,一起向父节点 "-10" 自荐。以此类推。

为什么 "20" 只能携带一棵子树?因为我们构造的是一条笔直的路径,如果左右子树都带上,那这条路就分叉了。

cpp 复制代码
class Solution {
public:
    int maxSum = INT_MIN;
    int helper(TreeNode* root) {
        if (!root) return 0;
        
        // 获取左右子树中的最大路径和
        int leftSum = max(0, helper(root->left));
        int rightSum = max(0, helper(root->right));
        // 计算当前子树的最大路径和
        int pathSum = root->val + leftSum + rightSum;
        maxSum = max(maxSum, pathSum);
        // 向父节点自荐
        return root->val + max(leftSum, rightSum);
    }

    int maxPathSum(TreeNode* root) {
        helper(root);
        return maxSum;
    }
};
相关推荐
tainshuai2 小时前
用 KNN 算法解锁分类的奥秘:从电影类型到鸢尾花开
算法·分类·数据挖掘
Coovally AI模型快速验证8 小时前
农田扫描提速37%!基于检测置信度的无人机“智能抽查”路径规划,Coovally一键加速模型落地
深度学习·算法·yolo·计算机视觉·transformer·无人机
pusue_the_sun8 小时前
数据结构:二叉树oj练习
c语言·数据结构·算法·二叉树
RaymondZhao348 小时前
【全面推导】策略梯度算法:公式、偏差方差与进化
人工智能·深度学习·算法·机器学习·chatgpt
zhangfeng11338 小时前
DBSCAN算法详解和参数优化,基于密度的空间聚类算法,特别擅长处理不规则形状的聚类和噪声数据
算法·机器学习·聚类
圣保罗的大教堂9 小时前
leetcode 2348. 全 0 子数组的数目 中等
leetcode
啊阿狸不会拉杆9 小时前
《算法导论》第 32 章 - 字符串匹配
开发语言·c++·算法
小学生的信奥之路10 小时前
洛谷P3817题解:贪心算法解决糖果分配问题
c++·算法·贪心算法
你知道网上冲浪吗11 小时前
【原创理论】Stochastic Coupled Dyadic System (SCDS):一个用于两性关系动力学建模的随机耦合系统框架
python·算法·数学建模·数值分析
地平线开发者12 小时前
征程 6 | PTQ 精度调优辅助代码,总有你用得上的
算法·自动驾驶