Leetcode 124 Binary Tree Maximum Path Sum 二叉樹最大路徑和
原題連結
題目描述
Given a binary tree, find the maximum path sum.
給出一棵二叉樹,計算其最大路徑和。
The path may start and end at any node in the tree.
路徑的起止結點必須位於樹內。
For example:
例如:
Given the below binary tree,
給出如下二叉樹,
1
/ \
2 3
Return 6.
返回6(sum path 2-1-3)。
解題思路
這個題目還是挺不好想的,我們需要找到問題的關鍵點。那麼對於二叉樹裡的一條子路徑,什麼是關鍵點呢?我們先來做一個假設,假設我們已經找到這個路徑path了,我認為關鍵點就是某一個結點是否處於這個路徑內。但是如何找這個path呢?我們不妨假設,我們正在處理的子樹的根結點root一定位於這個path內,我們計算當path一定經過了root時的最大路徑和max(root)。那麼max(root)該如何計算呢?我們假設我們已經求除了當path一定經過root->left時的最大路徑和max(root->left),也求除了當path一定經過root->right時的最大路徑和max(root->right),這時候,如果max(root->left)>0,那麼對於root而言,將root->left和root連線起來的path的和一定比root自己構成的path的和要大;同理,如果max(root->right)>0,那麼對於root而言,將root->left和root連線起來的path的和一定比root自己構成的path的和要大。然而對於一條路徑來說,root要麼跟root->left連線在一起,要麼跟root->right連線在一起,要麼root既不跟root->left也不跟root->right連線在一起,不然路徑會出現分叉。因此我們需要對root->val+max(root->left)、root->val、root->val+max(root->right)求出其中的最大值來作為max(root)的值。
有了如上的步驟之後,我們到底該如何確定二叉樹的最大路徑和呢?實際上,我們上述過程是求得了以某一個結點為根的子樹的最大路徑和,其中路徑的起點為根,終點為子樹中的某一結點,我們注意到這個過程中,我們每次都只是從根的左右子結點中選擇其中的一個來連線到path中,實際上,一個path是有可能既連線root->left,又連線root->right的,但是這種情況至多會出現在其中一個結點x上,否則就會出現路徑的分叉了。因此,我們在求的max(root->left)、max(root->right)之後,嘗試將root作為我們上面提到的x點,然後來計算由max(root->left)、max(root->right)、root->val可能構成的最大和tmp,然後判定tmp和當前快取好的max(最大路徑和),並更新max值即可。最後,這個max就是我們要求的最大路徑和。
演算法
- 如果root為NULL,返回0
- 遞迴呼叫1-5,求得maxSum(root->left)和maxSum(root->right)
- maxSum(root) = max(root->val, root->val + maxSum(root->left), root->val + maxSum(root->right))
- 判定root->val 、 maxSum(root->left)、maxSum(root->right)三者可能構成的最大和(必須包含root->val),是否大於目前快取的最大路徑和tmp,如果是則更新tmp
- 返回maxSum(root)的值
- 遞迴呼叫結束後,tmp的值就是最大路徑和
程式碼c
/**
* 計算二叉樹的最大路徑和
* @param : root 二叉樹根結點
* @return : 最大路徑和
*/
int maxPathSum(struct TreeNode *root) {
int maxChildPathSum(struct TreeNode *, int *);
if (root == NULL) return 0;
int tmpMax = root->val;
maxChildPathSum(root, &tmpMax);
return tmpMax;
}
/**
* 計算二叉樹子樹的最大路徑和以及整棵二叉樹的最大路徑和
* 子樹路徑必須以根結點開始,以樹中某一結點結束
* 二叉樹的最大路徑和的路徑,不必以根結點為開始結點
* @param : root 二叉樹根結點
* @param : tmpMax 暫存整棵二叉樹的最路徑和的變數的地址
* @return : 子樹的最大路徑和
*/
int maxChildPathSum(struct TreeNode *root, int *tmpMax) {
int max(int, int);
if (root == NULL) return 0;
/* 計算左右子樹的最大路徑和 */
int leftMax = maxChildPathSum(root->left, tmpMax);
int rightMax = maxChildPathSum(root->right, tmpMax);
/* 嘗試更新整棵二叉樹的最大路徑和 */
int tmp = root->val;
if (leftMax > 0) tmp += leftMax;
if (rightMax > 0) tmp += rightMax;
if (tmp > *tmpMax) *tmpMax = tmp;
/* 計算並返回子樹的最大路徑和 */
int maxRoot = max(root->val, max(root->val + leftMax, root->val + rightMax));
return maxRoot;
}
/* 求兩個數中較大的數字 */
int max(int arg1, int arg2) { return arg1 > arg2 ? arg1 : arg2; }
程式碼cpp
class Solution {
public:
/**
* 計算二叉樹的最大路徑和
* @param : root 二叉樹根結點
* @return : 最大路徑和
*/
int maxPathSum(TreeNode *root) {
if (root == NULL) return 0;
int tmpMax = root->val;
maxChildPathSum(root, &tmpMax);
return tmpMax;
}
private:
/**
* 計算二叉樹子樹的最大路徑和以及整棵二叉樹的最大路徑和
* 子樹路徑必須以根結點開始,以樹中某一結點結束
* 二叉樹的最大路徑和的路徑,不必以根結點為開始結點
* @param : root 二叉樹根結點
* @param : tmpMax 暫存整棵二叉樹的最路徑和的變數的地址
* @return : 子樹的最大路徑和
*/
int maxChildPathSum(TreeNode *root, int *tmpMax) {
if (root == NULL) return 0;
/* 計算左右子樹的最大路徑和 */
int leftMax = maxChildPathSum(root->left, tmpMax);
int rightMax = maxChildPathSum(root->right, tmpMax);
/* 嘗試更新整棵二叉樹的最大路徑和 */
int tmp = root->val;
if (leftMax > 0) tmp += leftMax;
if (rightMax > 0) tmp += rightMax;
if (tmp > *tmpMax) *tmpMax = tmp;
/* 計算並返回子樹的最大路徑和 */
int maxRoot = max(root->val, max(root->val + leftMax, root->val + rightMax));
return maxRoot;
}
/* 求兩個數中較大的數字 */
int max(int arg1, int arg2) { return arg1 > arg2 ? arg1 : arg2; }
};
測試資料
輸入:[2,1,3]
輸出: 6
輸入:[5,6,7,-4,null,-1,1,2]
輸出:19
輸入:[5,6,7,-4,null,null,-1,1,2]
輸出:18
輸入:[-5,6,7,-4,null,null,-1,1,2]
輸出:8
輸入:[1,-2,3]
輸出:4
解決情況
Lauguage | Status | Time |
---|---|---|
c | Accept | 20ms |
cpp | Accept | 32ms |
2015/7/14