124. 二叉樹中的最大路徑和
題目來源:力扣(LeetCode)https://leetcode-cn.com/problems/binary-tree-maximum-path-sum
題目
給定一個非空二叉樹,返回其最大路徑和。
本題中,路徑被定義為一條從樹中任意節點出發,達到任意節點的序列。該路徑至少包含一個節點,且不一定經過根節點。
示例 1:
輸入: [1,2,3]
1
/ \
2 3
輸出: 6
示例 2:
輸入: [-10,9,20,null,null,15,7]
-10
/ \
9 20
/ \
15 7
輸出: 42
解題思路
思路:遞歸
題目中所給出的路徑概念是指【一條從樹中任意節點出發,達到任意節點的序列。該路徑至少包含一個節點,且不一定經過根節點】。
也就是說,要求出路徑和,得計算節點能提供的最大貢獻值。
對於節點能提供的貢獻值,分為如下部分:
- 空節點提供的貢獻值為 0;
- 對於非空節點提供的貢獻值,等於當前節點的值與其子節點中提供最大貢獻值的和。
現在以示例 1 來分析說明下:
輸入: [1,2,3]
1
/ \
2 3
在這里葉子節點 2
,3
,能提供的貢獻值就是 2, 3。
而葉子節點 1,能夠提供的貢獻值為 1+2
或 1+3
。
那我們假設:如果節點 1 前面還有父節點,那么這里可能的路徑就會變成:
- 2 + 1 + 3
- 2 + 1 + 1 的父節點
- 3 + 1 + 1 的父節點
其中第一種情況,就是求節點的最大路徑和。這里節點的最大路徑和取決於該節點與其左右子節點的最大貢獻值之和。當然,在這里,如果子節點的貢獻值為負,則選擇不納入。因為負數的貢獻值添加進來反而會讓結果變小。
對於第二種和第三種情況來說,這里就是遞歸求得左右子節點的貢獻值,從中取更優的方案。
這里最主要的就是維護一個存儲最大路徑和的變量 max_path_sum
,遞歸的過程中維護更新這個值,從而求得最大值。
具體的代碼實現如下。
代碼實現
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def __init__(self):
# 存儲最大路徑和
self.max_path_sum = float('-inf')
def maxPathSum(self, root: TreeNode) -> int:
def max_contr(node):
# 遞歸求節點最大貢獻值
# 同時維護經過節點的最大路徑和
# 空節點的貢獻值為 0
if not node:
return 0
# 遞歸計算左子節點的貢獻值,
left = max(0, max_contr(node.left))
# 遞歸計算右子節點的貢獻值
right = max(0, max_contr(node.right))
# 經過當前節點的最大路徑和
self.max_path_sum = max(self.max_path_sum, left + node.val + right)
# 當前節點的貢獻值,取左右子節點中的更優方案
node_contr = node.val + max(0, max(left, right))
# 這里返回的貢獻值是給當前節點的上游節點
return node_contr
max_contr(root)
return self.max_path_sum
實現結果
總結
- 從題目中得到的信息可以知道,要求最大路徑和,需要求得節點能夠提供的貢獻值。
- 對於節點而言,提供的貢獻值分為兩部分:
- 空節點的貢獻值為 0;
- 對於非空節點而言,當前節點能提供的貢獻值為當前節點的值與其子節點中能提供的最大貢獻值之和
- 對於非空節點而言,我們需要遞歸的方法求得每個節點的貢獻值。同時,需要維護最大路徑和,在這里,該節點的路徑和取決於當前節點的值與其左右子節點的最大貢獻值。
- 這里需要注意:當貢獻值為負時,不計入節點的最大路徑和。
文章原創,如果覺得寫得還好,歡迎關注點贊。微信公眾號《書所集錄》同步更新,同樣歡迎關注點贊。