• LeetCode 热题 100 | 二叉树(终)


    目录

    1  二叉树小结

    1.1  模式一

    1.2  模式二

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

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


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

    二叉树小结

    菜鸟碎碎念

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

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

    代码一般都长这样:

    1. function(Treenode * root) {
    2. if (!root) return;
    3. root->val...
    4. function(root->left);
    5. function(root->left);
    6. ...
    7. }

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

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

    代码一般都长这样:

    1. function(Treenode * root) {
    2. if (!root) return;
    3. function(root->left);
    4. function(root->right);
    5. root->val...
    6. ...
    7. }

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

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

    解题思路:

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

    详细代码:

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

    1. bool lson = helper(root->left, p, q);
    2. bool rson = helper(root->right, p, q);

    相应的返回值如下:

    return lson || rson || (root == p || root == q);

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

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

    1. if ((lson && rson) || ((root == p || root == q) && (lson || rson))) {
    2. ans = root;
    3. }

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

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

    1. class Solution {
    2. public:
    3. TreeNode * ans;
    4. bool helper(TreeNode* root, TreeNode* p, TreeNode* q) {
    5. if (!root) return false;
    6. bool lson = helper(root->left, p, q);
    7. bool rson = helper(root->right, p, q);
    8. if ((lson && rson) || ((root == p || root == q) && (lson || rson))) {
    9. ans = root;
    10. }
    11. return lson || rson || (root == p || root == q);
    12. }
    13. TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    14. helper(root, p, q);
    15. return ans;
    16. }
    17. };

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

    解题思路:

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

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

    思路说明图:

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

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

    1. class Solution {
    2. public:
    3. int maxSum = INT_MIN;
    4. int helper(TreeNode* root) {
    5. if (!root) return 0;
    6. // 获取左右子树中的最大路径和
    7. int leftSum = max(0, helper(root->left));
    8. int rightSum = max(0, helper(root->right));
    9. // 计算当前子树的最大路径和
    10. int pathSum = root->val + leftSum + rightSum;
    11. maxSum = max(maxSum, pathSum);
    12. // 向父节点自荐
    13. return root->val + max(leftSum, rightSum);
    14. }
    15. int maxPathSum(TreeNode* root) {
    16. helper(root);
    17. return maxSum;
    18. }
    19. };

  • 相关阅读:
    RabbitMQ的工作队列有哪些?带你玩转工作队列(可学习、可复习、可面试)
    使用ORL人脸库,通过GRNN网络和HOG特征提取的人脸识别算法matlab仿真
    笔记--es6
    Time-Frequency Signal Analysis and Processing 笔记
    本地如何使用HTTPS进行调试
    Python3 笔记:字符串的 encode() 和 bytes.decode()
    微信小程序1(代码构成和基础组件和协同开发)
    [RCTF 2019]nextphp
    振南技术干货集:C语言的一些“骚操作”及其深层理解(3)
    零基础数据科学学习 Python 的 4 个阶段
  • 原文地址:https://blog.csdn.net/m0_64140451/article/details/136240895