題目來源
給定一個非空二叉樹,返回其最大路徑和。
本題中,路徑被定義為一條從樹中任意節點出發,沿父節點-子節點連接,達到任意節點的序列。
該路徑至少包含一個節點,且不一定經過根節點。
示例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....