zoukankan      html  css  js  c++  java
  • 算法图解——求二叉树中的最大路径和

    题目来源

    给定一个非空二叉树,返回其最大路径和。

    本题中,路径被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。

    该路径至少包含一个节点,且不一定经过根节点。

    示例1:

    输入:[1,2,3]
    
           1
          / 
         2   3
    
    输出:6

    示例2:

    输入:[-10,9,20,null,null,15,7]
    
        -10
        / 
       9  20
          /  
         15   7
    
    输出:42 
    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/binary-tree-maximum-path-sum
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

     题目分析

    有没有发现这一篇多了这一小节,捂脸......因为我怕你们看不懂题(我没看懂题)。

    理解该题目,关键是理解其中的“最大路径”,到底这个路径是怎么定义的?

    有人说,题目上不是说了吗?是呀,但是意思你真的看懂了吗?

    其实我举个小栗子你就知道了。

    有二叉树abc,a 是根结点(递归中的 root,当然,也可以加上e是a的父节点),bc 是左右子结点(代表其递归后的最优解)。
    最大的路径,可能的路径情况:

          e    
         /
        a
       / 
      b   c

    那么,最大路径只可能有三种情况:

    1. b + a + c。
    2. b + a + e(a 的父结点)。
    3. a + c + e (a 的父结点)。

    为什么是这样呢?下面做一些说明:

    其中情况 1,表示如果不联络父结点的情况,或本身是根结点的情况,即没有父节点。这种情况是没法递归的,但是结果有可能是全局最大路径和。

    情况 2 和 3,递归时计算 a+b 和 a+c,选择一个更优的方案然后加上e(如果a有父节点的话)返回。

    这样其实就得先比较左右子树的最大路径和,然后再和当前全局最大路径和比较,大的话,可以再往上递归。那么,这里为什么要和全局最大路径和做比较呢?对喽,因为结点有可能是负值,最大和肯定就要想办法舍弃负值(max(0, x))max(0,x))。

    但是上面 3 种情况,无论哪种,a 作为联络点,都不能够舍弃。

    题目解答

    C++:/** * Definition for a binary tree node. * struct TreeNode {

     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
     *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
     *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
     * };
     */
    class Solution {
    
    public:
        int maxSum = INT_MIN;
      //比较两者取较大值
    int max(int a,int b){ return a>b?a:b; }   //自己的递归函数 int mymax(TreeNode * root){
        //遇到叶子节点就返回0;
    if(root==NULL){ return 0; }
         //左右子节点分别递归;之所以和0比较就是,如果子树的最大径和是负数,那么就舍弃掉,你是负的要你何用?大家说是不是?
    int leftSum = max(0,mymax(root->left)); int rightSum = max(0,mymax(root->right));
         //计算当前最大路径和为左路径和+右路径和+该节点值,因为不确定该节点是否有父节点。所以先计算出来存起来备用。
    int curSum = leftSum+rightSum+root->val;
        //比较当前最大路径和 和 历史最大路径和;如果当前最大路径和较大,那么将全局历史最大路径和更新,否则不变,但是不管哪种,
        //返回的值都要加上root的值
    maxSum
    = max(maxSum, curSum); return max(leftSum,rightSum)+root->val; } int maxPathSum(TreeNode* root) { mymax(root); return maxSum; } };

    可以举例分析:

        a
       / 
      b   c

    当为:

        2
       / 
      1   3
    //最大值为6
        2
       / 
      1   -1
    //最大值为3
        -2
       / 
      1   3
    //最大值为3

    通过以上例子,就能知道最后两步 maxSum = max(maxSum, curSum);       return max(leftSum,rightSum)+root->val; 的意义了。

    over....

  • 相关阅读:
    聚集索引
    第一天 尝试Thread
    sql 分区函数
    sql 查询表定义
    千万数量级分页存储过程
    成语解释
    sql 分组查询满足条件所以数据
    sql存储过程
    联表更新的反思
    从表保存了主表的id,以分号分隔,怎么样用一条sql搞定主表满足条件的查询? 不希望单独写存储过程,或者后台拆成int后传进来,就一条sql 搞定,一条
  • 原文地址:https://www.cnblogs.com/gjmhome/p/14157616.html
Copyright © 2011-2022 走看看