LintCode 376. Binary Tree Path Sum

博客围绕二叉树路径和问题展开,给定二叉树,需找出节点和等于给定目标值的所有路径,路径需从根节点到叶节点。文中给出示例展示不同输入下的输出情况,还介绍了使用DFS(深度优先搜索)的解法。
  1. Binary Tree Path Sum
    中文English
    Given a binary tree, find all paths that sum of the nodes in the path equals to a given number target.

A valid path is from root node to any of the leaf nodes.

Example
Example 1:

Input:
{1,2,4,2,3}
5
Output: [[1, 2, 2],[1, 4]]
Explanation:
The tree is look like this:
1
/
2 4
/
2 3
For sum = 5 , it is obviously 1 + 2 + 2 = 1 + 4 = 5
Example 2:

Input:
{1,2,4,2,3}
3
Output: []
Explanation:
The tree is look like this:
1
/
2 4
/
2 3
Notice we need to find all paths from root node to leaf nodes.
1 + 2 + 2 = 5, 1 + 2 + 3 = 6, 1 + 4 = 5
There is no one satisfying it.

解法1:DFS
代码如下:

/**
 * Definition of TreeNode:
 * class TreeNode {
 * public:
 *     int val;
 *     TreeNode *left, *right;
 *     TreeNode(int val) {
 *         this->val = val;
 *         this->left = this->right = NULL;
 *     }
 * }
 */


class Solution {
public:
    /*
     * @param root: the root of binary tree
     * @param target: An integer
     * @return: all valid paths
     */
    vector<vector<int>> binaryTreePathSum(TreeNode * root, int target) {
        if (!root) return vv;
        vector<int> v;
        helper(root, target, v);
        return vv;
    }

private:
    vector<vector<int>> vv;
    void helper(TreeNode * root, int target, vector<int> & v) {
        if (!root) return;
        if (target == root->val && !root->left && !root->right) {
            v.push_back(target);
            vv.push_back(v);
            v.pop_back();
            return;
        }
        v.push_back(root->val);
        helper(root->left, target - root->val, v);
        helper(root->right, target - root->val, v);
        v.pop_back();
    }
};
你的代码试图解决 **“二叉树中的最大路径和”**(LeetCode #124),整体思路是正确的:使用递归计算每个节点的最大单边贡献,并在过程中更新全局最大路径和。 但是,存在几个关键问题会导致 **错误或边界情况失败**。下面我将: 1. 逐行分析你代码的问题 2. 给出正确且优化的版本 3. 解释核心思想 4. 提供测试用例验证 --- ## ❌ 存在的问题 ### 🔴 1. 使用 `np.inf` 不安全 ```python import numpy as np ... leftContrib = -np.inf ``` - **问题**:LeetCode 环境虽然支持 NumPy,但你不应该依赖它来表示负无穷。 - 更标准、更轻量的方式是使用 Python 内置的 `float('-inf')`。 - 此外,当 `leftContrib = -np.inf` 时,后续 `if leftContrib > 0:` 虽然逻辑上不会进,但容易引起误解。 ### 🔴 2. 单节点处理不一致 ```python if root.left is None and root.right is None: return root.val, max(root.val, maxSum) ``` - 这里返回的是 `(root.val, max(root.val, maxSum))`,但初始传入的 `maxSum = -np.inf` 是全局最大值。 - 问题是:你在叶子节点就尝试更新 `maxSum`,但在非叶子节点又重新比较一次 `thisMaxSum`,这没问题,但逻辑重复。 ### 🔴 3. `maxContrib` 返回值设计混乱 ```python return root.val + max(leftContrib, rightContrib, 0), max(thisMaxSum, maxSum) ``` - 第二个返回值是不断向上传递的 `maxSum`,这种“通过参数传递并层层返回”的方式容易出错,可读性差。 - 实际上我们只需要一个 **nonlocal 变量或类变量** 来记录全局最大路径和即可。 ### 🔴 4. 根节点特殊判断多余 ```python if root is None: return 0 if root.left is None and root.right is None: return root.val ``` - 第一个:`root is None` 应该返回什么?题目保证至少一个节点,可以忽略,但返回 `0` 错误!应为 `-inf` 或抛异常。 - 第二个:没必要单独处理,DFS 自然会处理单节点情况。 --- ## ✅ 正确且优化后的版本 ```python # Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def maxPathSum(self, root: Optional[TreeNode]) -> int: self.max_sum = float('-inf') # 全局最大路径和 def dfs(node): """返回从当前节点出发向下的最大单边路径和""" if not node: return 0 # 递归获取左右子树的最大单边贡献,负数则舍去(取0) left_gain = max(dfs(node.left), 0) right_gain = max(dfs(node.right), 0) # 计算以当前节点为顶点的Z形路径总和 current_path_sum = node.val + left_gain + right_gain # 更新全局最大值 self.max_sum = max(self.max_sum, current_path_sum) # 返回经过当前节点向上的最大单边路径和(只能走一边) return node.val + max(left_gain, right_gain) dfs(root) return self.max_sum ``` --- ## ✅ 为什么这个版本更好? | 特性 | 说明 | |------|------| | ✅ `self.max_sum = float('-inf')` | 安全初始化,能处理全负数情况 | | ✅ `max(dfs(...), 0)` | 自动过滤负贡献的子树 | | ✅ `current_path_sum = node.val + left + right` | 当前节点作为路径顶部 | | ✅ `return node.val + max(left, right)` | 向上传递的是最大单边路径 | | ✅ 使用 `self.max_sum` 避免层层传递 `maxSum` | 更清晰、不易出错 | --- ## 🧪 测试用例验证 ### 示例 1: ```text -10 / \ 9 20 / \ 15 7 ``` - 最大路径:`15 -> 20 -> 7 = 42` - 输出:`42` ✅ ### 示例 2: ```text -3 \ -1 ``` - 路径:`-1`(必须选一个节点) - 输出:`-1` ✅ ### 示例 3: ```text 1 / \ 2 3 ``` - 路径:`2->1->3 = 6` - 输出:`6` ✅ --- ## 🔍 关键理解 > ⭐ **最大路径和不一定经过根节点!** 我们枚举每一个节点作为“路径最高点”(即路径在此转折向下),然后计算: ``` 路径和 = 左子树正贡献 + 当前节点 + 右子树正贡献 ``` 而向上传递的值只能是: ``` 向上返回 = 当前节点 + max(左贡献, 右贡献) // 只能走一边 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值