华为机考题:二叉树的最大路径和

题目描述

给定一棵非空二叉树,每个节点上有一个整数值(可能为负数),请你找出其中最大路径和。

路径被定义为一条从树中任意节点出发,沿父节点-子节点连接,到达任意节点的序列。同一个节点在一条路径序列中至多出现一次 。该路径至少包含一个节点,且不一定经过根节点。

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

输入描述

输入为按层序遍历 给出的二叉树节点值,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;
}
相关推荐
程序猿编码2 小时前
不用 PyTorch!纯 C 实现 N 维张量 + 反向传播,完成手写数字识别训练
c语言·人工智能·pytorch·神经网络·卷积神经网络·大模型推理
2601_962218612 小时前
深入理解C++中的thread_local线程局部变量的应用
开发语言·c++
无名猿2 小时前
C++ lambda 捕获列表详解:值捕获、引用捕获、初始化捕获与悬垂引用
c++·现代c++·语法基础·踩坑记录
lengxuenong3 小时前
枚举例题分析
c++·算法·青少年编程
繁华的地方不一定留下你的脚印3 小时前
C++线程如何安全停止与唤醒:std::jthread、stop_token与condition_variable
开发语言·c++
Navigator_Z3 小时前
LeetCode //C - 1269. Number of Ways to Stay in the Same Place After Some Steps
c语言·算法·leetcode
沫璃染墨3 小时前
《从零入门Linux系统篇(五十一):线程篇·四——pthread线程库详解:从线程创建到终止与分离》
linux·运维·服务器·开发语言·c++·系统架构·线程
shada4 小时前
CMake指定 MSVC 工具集与 Windows SDK
c++·windows
垆边人似月.4 小时前
华为机考题:矩阵中的最长递增路径
c语言·c++