XingHuiSama の 宝藏之地
首页项目归档照片墙音乐说说杂谈友链关于
封面

Leetcode一百题——路径总和 III

写作时间:2026-04-29 17:39:02
# C++
# Leetcode
# 题解

给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。

路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

示例 1:

‍

输入:root = [10,5,-3,3,2,null,11,3,-2,null,1], targetSum = 8
输出:3
解释:和等于 8 的路径有 3 条,如图所示。

示例 2:

输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:3

提示:

  • 二叉树的节点个数的范围是 [0,1000]
  • -109 <= Node.val <= 109
  • -1000 <= targetSum <= 1000

‍

1. 算法核心思想

本题要求寻找二叉树中节点值之和等于 targetSum 的路径数量。路径方向必须向下,但起点和终点可以是任意节点。为了优化时间与空间复杂度,本解法采用了前缀和与回溯的思想。

  • 前缀和(Prefix Sum): 在树的遍历过程中,记录从根节点到当前节点的路径总和。若要求某一段子路径的节点和等于 targetSum,等价于寻找在当前路径上,是否存在一个历史前缀和,使得 当前节点前缀和 - 历史前缀和 = targetSum。
  • 传引用与回溯(Backtracking): 为了避免在每次递归调用时复制数组(导致空间和时间复杂度大幅增加),全局使用唯一的 vector 并通过引用(&)传递。 由于左右子树的路径是相互独立的,当一条分支遍历结束,准备返回上一层时,必须将当前节点产生的前缀和从数组中移除(即状态还原/回溯),以确保不影响其他分支的计算。

‍
‍

2. 代码逻辑拆解

  • 主函数 pathSum:

    • 初始化计数器 count 为 0。
    • 声明存储前缀和的数组 arr。
    • 关键初始化:在数组中预先压入 0。这是为了处理“从根节点开始的路径刚好等于 targetSum”的情况(即 当前前缀和 - 0 = targetSum)。
  • 递归函数 fun1:

    • 终止条件:若当前节点为空,直接返回。
    • 累加前缀和:将当前节点的值累加到 sum 中,得到从根节点到当前节点的完整前缀和。
    • 查找合法路径:遍历 arr 中存储的历史前缀和,若 sum - arr[i] == targetSum,说明存在一条满足条件的子路径,count 自增。
    • 状态记录:将当前 sum 压入 arr,供后续的子孙节点匹配使用。
    • 向下递归:继续遍历左子树和右子树。
    • 回溯(状态还原):在退出当前递归层之前,执行 arr.pop_back(),将当前节点的 sum 移出数组,保证该分支的数据不会污染其他同级或上级分支。
class Solution {
public:
    int count;
    
    int pathSum(TreeNode* root, int targetSum) {
        count = 0;
        vector<long long> arr; 
        arr.push_back(0); 
        fun1(root, arr, 0, targetSum);
        return count;
    }

    void fun1(TreeNode* node, vector<long long>& arr, long long sum, int targetSum) {
        if (node == NULL) {
            return;
        }
        
        sum += node->val;

        // 查找是否存在符合条件的历史前缀和
        for (int i = 0; i < arr.size(); i++) {
            if (sum - arr[i] == targetSum) {
                count++;
            }
        }

        // 记录当前前缀和
        arr.push_back(sum);

        // 递归遍历左右子树
        fun1(node->left, arr, sum, targetSum);
        fun1(node->right, arr, sum, targetSum);

        // 回溯:移除当前节点的前缀和,避免影响其他分支
        arr.pop_back();
    }
};

3. 复杂度分析与细节说明

  • 时间复杂度:O(N⋅H) 其中 N 为二叉树的节点总数,H 为树的高度。遍历每个节点耗时 O(N);在每个节点处,需要遍历长度最大为 H 的前缀和数组。对于平衡二叉树,时间复杂度为 O(NlogN);最坏情况(树退化为链表)下为 O(N2)。
  • 空间复杂度:O(H) 由于通过引用传递数组,未开辟额外数组空间。主要空间开销为递归调用栈的深度以及 arr 数组的长度,二者均不超过树的高度 H。

‍

avatar

XingHuiSama

在代码、学术与分子动力学模拟间穿梭的普通人。近期正埋头于 GROMACS 模拟研究与神经网络计算。

RECOMMENDED

GROMACS 2025 分子动力学模拟初探2222

2026-03-24 07:00:45

Computational Chemistry Tool 工具二介绍

2026-04-01 07:00:23

Leetcode一百题——字母异位词分组

2026-04-07 15:34:18

Table of Contents