题目描述
给定一棵非空二叉树,每个节点上有一个整数值(可能为负数),请你找出其中最大路径和。
路径被定义为一条从树中任意节点出发,沿父节点-子节点连接,到达任意节点的序列。同一个节点在一条路径序列中至多出现一次 。该路径至少包含一个节点,且不一定经过根节点。
路径和是路径中各节点值的总和。
输入描述
输入为按层序遍历 给出的二叉树节点值,null 表示空节点。
例如:-10 9 20 null null 15 7
表示:
text
-10
/ \
9 20
/ \
15 7
输出描述
一个整数,表示最大路径和。
示例
输入:
text
-10 9 20 null null 15 7
输出:
text
42
说明: 最优路径为 15 -> 20 -> 7,路径和为 15 + 20 + 7 = 42。
输入:
text
2 -1
输出:
text
2
说明: 最优路径为节点 2 本身。
输入:
text
-3
输出:
text
-3
说明: 只有一个节点,路径和即为该节点值。
C++ 解决方法(DFS 后序遍历)
思路: 对于任意节点 node,经过它的路径最大和由三部分组成:
-
左子树能提供的最大单边路径和 (
leftGain) -
右子树能提供的最大单边路径和 (
rightGain) -
节点自身的值
我们定义 DFS 函数的返回值:以当前节点为起点,向下延伸的最大单边路径和(只能选左或右一条边,因为父节点也要参与路径)。
在递归过程中,对于每个节点,计算:
text
当前节点作为"拐点"的路径和 = node->val + max(0, leftGain) + max(0, rightGain)
用全局变量 maxSum 记录所有节点中这个值的最大值。
关键点:
-
当子树贡献为负时,选择不延伸(取 0)。
-
返回值只能选左右子树中较大的一边(不能同时返回两边,否则路径会在当前节点分叉,无法继续向上)。
时间复杂度 O(n),空间复杂度 O(h)(递归栈深度)。
cpp
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <queue>
#include <algorithm>
#include <climits>
using namespace std;
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
class Solution {
public:
int maxSum = INT_MIN;
int maxPathSum(TreeNode* root) {
maxGain(root);
return maxSum;
}
private:
// 返回以 node 为起点向下延伸的最大单边路径和
int maxGain(TreeNode* node) {
if (node == nullptr) return 0;
// 递归计算左右子树的最大贡献值,负贡献直接舍弃(取 0)
int leftGain = max(0, maxGain(node->left));
int rightGain = max(0, maxGain(node->right));
// 以当前节点为"拐点"的路径和(左右两边都可以走)
int currentPathSum = node->val + leftGain + rightGain;
maxSum = max(maxSum, currentPathSum);
// 返回给父节点:只能选一条边
return node->val + max(leftGain, rightGain);
}
};
// 根据层序遍历数组构建二叉树
TreeNode* buildTree(const vector<string>& tokens) {
if (tokens.empty() || tokens[0] == "null") return nullptr;
TreeNode* root = new TreeNode(stoi(tokens[0]));
queue<TreeNode*> q;
q.push(root);
int i = 1;
while (!q.empty() && i < (int)tokens.size()) {
TreeNode* cur = q.front();
q.pop();
// 左子节点
if (i < (int)tokens.size() && tokens[i] != "null") {
cur->left = new TreeNode(stoi(tokens[i]));
q.push(cur->left);
}
i++;
// 右子节点
if (i < (int)tokens.size() && tokens[i] != "null") {
cur->right = new TreeNode(stoi(tokens[i]));
q.push(cur->right);
}
i++;
}
return root;
}
int main() {
string line;
getline(cin, line);
// 按空格拆分输入
vector<string> tokens;
istringstream iss(line);
string token;
while (iss >> token) {
tokens.push_back(token);
}
TreeNode* root = buildTree(tokens);
Solution sol;
cout << sol.maxPathSum(root) << endl;
return 0;
}