题目描述

二叉树中的 路径 被定义为一条节点序列,序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。

路径和 是路径中各节点值的总和。

给你一个二叉树的根节点 root ,返回其 最大路径和

示例 1:

img

1
2
3
输入:root = [1,2,3]
输出:6
解释:最优路径是 2 -> 1 -> 3 ,路径和为 2 + 1 + 3 = 6

具体见题目详解

算法思路

这是刷HOT100以来貌似碰到的第一个“困难”题目,不过所幸最后还是做出来了,我的思路很简单,首先肯定能想到这是个动态规划,但为什么是深搜呢?可以看我下面的分析。

计自身节点值为selfval,左儿子节点路径值为leftval,右儿子节点路径值为rightval,则有:

  1. 对于一个节点,如果最终的路径中,其作为父节点,那么很明显,最大值必然在{selfval、selfval+leftval、selfval+rightval、selfval+leftval+rightval}中间产出。
  2. 如果其不是父节点,那么其只能贡献selfval, selfval + leftval, selfval + rightval之间最大的那一方给总路径,因为此时不然不可能同时拥有左右两个路径的值。
  3. 既然要知道leftvalrigthval的大小关系,那么必然需要在求出最大值之前先求出后代的相应最大值,这样才能符合dp的思想,因此需要使用深搜。

我写出来的代码思路上和题解给的类似,但是还是存在一些不足,导致速率比较慢,源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
void backsequence(TreeNode* root) {
if (root == nullptr) {
return;
}
int leftmax = INT16_MIN;
int rightmax = INT16_MIN;
if (root->left != nullptr) {
backsequence(root->left);
leftmax = max_lr[root->left];
}
if (root->right != nullptr) {
backsequence(root->right);
rightmax = max_lr[root->right];
}
max_lr[root] = max(root->val, max(root->val+leftmax, root->val+rightmax));
ans = max(ans, max(root->val, max(max(root->val + leftmax, root->val + rightmax), root->val + leftmax + rightmax)));
}
public:
unordered_map<TreeNode*, int> max_lr;
int ans;
int maxPathSum(TreeNode* root) {
ans = INT16_MIN;
//后续遍历递归的方式解决问题
backsequence(root);
return ans;
}
};

然后我又让claude3.7按照我的思路优化一下我的算法,他给出了如下结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
private:
int maxSum;

int maxGain(TreeNode* node) {
if (!node) return 0;

// 递归计算左右子树的最大贡献值
// 只有在最大贡献值大于 0 时,才会选取对应子节点
int leftGain = max(maxGain(node->left), 0);
int rightGain = max(maxGain(node->right), 0);

// 节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值
int priceNewPath = node->val + leftGain + rightGain;

// 更新答案
maxSum = max(maxSum, priceNewPath);

// 返回节点的最大贡献值
return node->val + max(leftGain, rightGain);
}

public:
int maxPathSum(TreeNode* root) {
maxSum = INT_MIN;
maxGain(root);
return maxSum;
}
};

比我的可读性好得多,也很容易理解,相信大家一看便会!