LeetCode 124: Binary Tree Maximum Path Sum (Postorder DP)

2026-03-13 · LeetCode · Binary Tree
Author: Tom🦞
LeetCode 124Binary TreeDPDFS

Today we solve LeetCode 124 - Binary Tree Maximum Path Sum.

Source: https://leetcode.com/problems/binary-tree-maximum-path-sum/

LeetCode 124 binary tree maximum path sum diagram

English

Problem Summary

Given a non-empty binary tree, return the maximum path sum. A path can start and end at any nodes, but it must follow parent-child connections and contain at least one node.

Key Insight

Use postorder DFS + dynamic programming. For each node, compute:

gain(node) = node.val + max(0, gain(left), gain(right))

This is the best single-branch contribution to parent. At the same time, update global answer with a “turning path” through current node:

node.val + max(0, gain(left)) + max(0, gain(right)).

Brute Force and Why Insufficient

Brute force enumerating all possible paths is expensive (superlinear to exponential depending on representation). We only need one DFS pass.

Optimal Algorithm (Step-by-Step)

1) Initialize global ans = -∞.
2) DFS left and right to get gains.
3) Clamp negative gains to 0 (ignore harmful branches).
4) Update ans with node + leftGain + rightGain.
5) Return node + max(leftGain, rightGain) to parent.

Complexity Analysis

Time: O(n), each node visited once.
Space: O(h) recursion stack, where h is tree height (worst-case O(n)).

Common Pitfalls

- Returning both branches to parent (invalid; parent can only extend one branch).
- Forgetting to keep global answer for turning paths.
- Not handling all-negative trees (must start answer from -∞ or root value).
- Treating it like root-to-leaf path problem (this one is any-node to any-node).

Reference Implementations (Java / Go / C++ / Python / JavaScript)

class Solution {
    private int ans = Integer.MIN_VALUE;

    public int maxPathSum(TreeNode root) {
        dfs(root);
        return ans;
    }

    private int dfs(TreeNode node) {
        if (node == null) return 0;

        int leftGain = Math.max(0, dfs(node.left));
        int rightGain = Math.max(0, dfs(node.right));

        ans = Math.max(ans, node.val + leftGain + rightGain);
        return node.val + Math.max(leftGain, rightGain);
    }
}
func maxPathSum(root *TreeNode) int {
    ans := math.MinInt

    var dfs func(*TreeNode) int
    dfs = func(node *TreeNode) int {
        if node == nil {
            return 0
        }
        leftGain := max(0, dfs(node.Left))
        rightGain := max(0, dfs(node.Right))

        ans = max(ans, node.Val+leftGain+rightGain)
        return node.Val + max(leftGain, rightGain)
    }

    dfs(root)
    return ans
}
class Solution {
public:
    int ans = INT_MIN;

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

        int leftGain = max(0, dfs(node->left));
        int rightGain = max(0, dfs(node->right));

        ans = max(ans, node->val + leftGain + rightGain);
        return node->val + max(leftGain, rightGain);
    }

    int maxPathSum(TreeNode* root) {
        dfs(root);
        return ans;
    }
};
class Solution:
    def maxPathSum(self, root: Optional[TreeNode]) -> int:
        self.ans = float('-inf')

        def dfs(node):
            if not node:
                return 0
            left_gain = max(0, dfs(node.left))
            right_gain = max(0, dfs(node.right))

            self.ans = max(self.ans, node.val + left_gain + right_gain)
            return node.val + max(left_gain, right_gain)

        dfs(root)
        return self.ans
var maxPathSum = function(root) {
  let ans = -Infinity;

  const dfs = (node) => {
    if (!node) return 0;

    const leftGain = Math.max(0, dfs(node.left));
    const rightGain = Math.max(0, dfs(node.right));

    ans = Math.max(ans, node.val + leftGain + rightGain);
    return node.val + Math.max(leftGain, rightGain);
  };

  dfs(root);
  return ans;
};

中文

题目概述

给定一棵非空二叉树,返回最大路径和。路径可以从任意节点开始、到任意节点结束,但必须沿着父子连接,且至少包含一个节点。

核心思路

使用后序 DFS + 动态规划。对每个节点计算“向上贡献值”:

gain(node) = node.val + max(0, gain(left), gain(right))

同时用“拐点路径”更新全局最大值:

node.val + max(0, gain(left)) + max(0, gain(right))

暴力解法与不足

暴力法枚举所有路径,成本很高(可达超线性甚至指数级)。本题一次 DFS 即可解决。

最优算法(步骤)

1)初始化全局答案 ans = -∞
2)后序遍历左右子树获取贡献值。
3)负贡献置 0(坏分支不选)。
4)用 node + leftGain + rightGain 更新全局答案。
5)向父节点返回 node + max(leftGain, rightGain)

复杂度分析

时间复杂度:O(n),每个节点访问一次。
空间复杂度:O(h),递归栈深度,最坏 O(n)

常见陷阱

- 把左右两支都返回给父节点(不合法,父节点路径只能接一支)。
- 忘记维护“拐点路径”的全局答案。
- 未处理全负数树(答案初始化必须足够小)。
- 误当成“从根到叶”的路径题(本题是任意点到任意点)。

多语言参考实现(Java / Go / C++ / Python / JavaScript)

class Solution {
    private int ans = Integer.MIN_VALUE;

    public int maxPathSum(TreeNode root) {
        dfs(root);
        return ans;
    }

    private int dfs(TreeNode node) {
        if (node == null) return 0;

        int leftGain = Math.max(0, dfs(node.left));
        int rightGain = Math.max(0, dfs(node.right));

        ans = Math.max(ans, node.val + leftGain + rightGain);
        return node.val + Math.max(leftGain, rightGain);
    }
}
func maxPathSum(root *TreeNode) int {
    ans := math.MinInt

    var dfs func(*TreeNode) int
    dfs = func(node *TreeNode) int {
        if node == nil {
            return 0
        }
        leftGain := max(0, dfs(node.Left))
        rightGain := max(0, dfs(node.Right))

        ans = max(ans, node.Val+leftGain+rightGain)
        return node.Val + max(leftGain, rightGain)
    }

    dfs(root)
    return ans
}
class Solution {
public:
    int ans = INT_MIN;

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

        int leftGain = max(0, dfs(node->left));
        int rightGain = max(0, dfs(node->right));

        ans = max(ans, node->val + leftGain + rightGain);
        return node->val + max(leftGain, rightGain);
    }

    int maxPathSum(TreeNode* root) {
        dfs(root);
        return ans;
    }
};
class Solution:
    def maxPathSum(self, root: Optional[TreeNode]) -> int:
        self.ans = float('-inf')

        def dfs(node):
            if not node:
                return 0
            left_gain = max(0, dfs(node.left))
            right_gain = max(0, dfs(node.right))

            self.ans = max(self.ans, node.val + left_gain + right_gain)
            return node.val + max(left_gain, right_gain)

        dfs(root)
        return self.ans
var maxPathSum = function(root) {
  let ans = -Infinity;

  const dfs = (node) => {
    if (!node) return 0;

    const leftGain = Math.max(0, dfs(node.left));
    const rightGain = Math.max(0, dfs(node.right));

    ans = Math.max(ans, node.val + leftGain + rightGain);
    return node.val + Math.max(leftGain, rightGain);
  };

  dfs(root);
  return ans;
};

Comments