算法图解——求二叉树中的最大路径和
题目来源
给定一个非空二叉树,返回其最大路径和。
本题中,路径被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。
该路径至少包含一个节点,且不一定经过根节点。
示例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
那么,最大路径只可能有三种情况:
- b + a + c。
- b + a + e(a 的父结点)。
- 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....