Leetcode 每日一题:Binary Tree Maximum Path Sum

写在前面:

又是一周的周末啦,题主当然又是被迫与同学们参加了很多社交活动。周五去参加了 USC 电影学院同学的电影放映分享,感叹与我同龄的人都已经成为小小制片老板了我还在哭兮兮的敲代码~~这就是人与人之间的残差嘛——

周六晚上是 USC Trojans Football 校队的第一场比赛,继上一场在 Las Vegas 拿下全美第 13 LSU 之后,我们在这个赛季的一个主场也是 48 - 0 零封了 Utah State。Trojans 今年有机会在新的联赛跻身全美 12 强季后赛,争夺一下赛区冠军和全国冠军呢!!Trojans Fight On!

OK 题归正传,今天我们正式进入 Tree 类的题目分享,今天这道题目是属于比较难,但比较代表性的 Tree 题目代表。来源于比较古早的 Leetcode 题目,做对他做会他对理解 recursion 和 Tree 类的问题非常有帮助,就让我们一起来看看吧!

题目介绍:

题目信息:

题目问题:

  • 给定一个 Tree,每一个 TreeNode 都有固定的一个 value
  • Path Sum 值得是在一段 traverse 路径下,所有的 TreeNode val 的累加综合
  • 求:最大的 Path Sum
  • 限定条件:每一个 Node 只能出现在一种 Path Sum 中,不可以重复计算

题目想法:

Brute Force:

我们首先可以想到,遍历所有的树的节点,然后针对每一个节点,找出所有和他相连的可能的 node,组成所有可能的 path,再在这些 path 中选择最大的 PathSum 作为答案。虽然这是一种可行的解决方法,但是 Runtime 会是 遍历整个树 O(n), 乘上每一个点都要再遍历一次树 O(n) 成为 O(n^2), 上来说并不优秀,并且我们其实做了很多重复的计算,例如当我们计算一个子节点的时候,他的父节点能选择的 PathSum 其实就只有两个 子节点 PathSum 更大的那一个加上他自己,并不需要再对所有的点进行一次遍历。所以我们可以针对这个特性对寻找答案进行一个优化

优化想法:

我们首先想到,在当前节点 root 下,他所可能产生的最大 PathSum 有四种可能来源

  • 他的 PathSum 来源于 left subtree 最大sum + right subtree 最大 sum + 自己
  • 他的 PathSum 来源于 left subtree 最大sum + 自己
  • 他的 PathSum 来源于 right subtree 最大sum + 自己
  • 他的 PathSum 来源于 他自己

这就意味着,我们在每一个节点,都需要获得他的 两个子树的最大获得,即在这个子树下能产生的最大获得是多少。

同时,因为TreeNode 的 value 有正有负,并且我们在考虑他们的加法最大,所以,我们可以直接忽略掉负数的贡献,因为他们一定会拉低数值。所以,在考虑单一 subtree 对最大 sum 的贡献时,我们只需要考虑 >= 0 子树元素的贡献即可。

既然这样,我们可以利用 bottom-up 的 recursion 方法,计算每一层的 左右子树 所能提供的最大 sum 获得,去掉小于 0 的部分。又因为如果上层需要使用当前 root 作为路径,他只能选取当前 root 的其中一个 subtree 作为 gain。所以,在当前 root 能为上一层所贡献的最大 sum可以表示为:

max(0, leftSubTreeGain) + root->val, max(0, rightSubTreeGain) + root->val))

再者,每一个 root 在自己层级,都可能可以 form 一个 最大 PathSum 的 path 出来,所以我们需要一个全局变量 MaxSum,在每次计算当前层的 左右最大贡献以后,计算并更新在当前层所能产生的最大 MaxSum 的值:

maxSum = max(maxSum, (leftMax + rightMax + root->val))

注意:

MaxSum 和 return 到再上一层的 MaxGain 是不同的概念:

  • MaxSum 指使用当前节点和以下层可以产生的最大 PathSum 结果,是直接的结果
  • MaxGain 指上层使用当前或以下节点可以获得的最大 Sum 的路径和,是部分的结果 

如果大家觉的我的文字讲解不够清晰的话,Github 上有带有图示讲解的详细答案,可以从以下访问:https://leetcode.com/problems/binary-tree-maximum-path-sum/editorial/

题目解法:

  • 定义 MaxSum 全局变量为 INT_MIN
  • traverse 整个树:
    • 在每一个 head节点中:
      • maxLeftGain = max(0, gain(head->left))
      • maxRightGain = max(0, gain(head->right))
      • maxSum = max(maxSum, maxLeftGain + maxRIghtGain + head->val)
      • 返回 次节点最大路径获得 max(maxLeftGain, maxRightGain) + head->val
  • 返回 MaxSum

题目代码:

/**
 * 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 getMaxSumPath(TreeNode* head){
        //there is no route
        if(head == nullptr){
            return 0;
        }
        
        //traverse left, and right, we only consider the contribution >= 0 to be considered
        int gainFromLeft = max(0, getMaxSumPath(head->left));
        int gainFromRight = max(0, getMaxSumPath(head->right));
        
        //determine whether we should update the maxSum from current path:
        //a route is consist of left subtree, right subtree and itself:
        maxSum = max(maxSum, gainFromLeft + gainFromRight + head->val);
        
        //return the current gain to the upper level:
        return max(gainFromLeft + head->val, gainFromRight + head->val);
    }
    
    int maxPathSum(TreeNode* root) {
        getMaxSumPath(root);
        return maxSum;
    }
};
  • Runtime: O(N)
  • Space: O(1)
  • 23
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值