news 2026/10/15 20:58:30

LeetCode 437路径总和III:前缀和与哈希表优化解法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LeetCode 437路径总和III:前缀和与哈希表优化解法

1. 题目背景与核心问题

LeetCode 437题"路径总和 III"是二叉树类问题中的经典题目,主要考察对树结构的遍历和路径统计能力。题目要求:给定一个二叉树的根节点和一个目标和,找出路径和等于给定值的路径数量。这里的路径不需要从根节点开始,也不需要在叶子节点结束,但必须保证路径方向是向下的(只能从父节点到子节点)。

这道题在面试中出现频率较高,因为它能同时考察候选人对递归、深度优先搜索(DFS)以及前缀和等算法的掌握程度。我在第一次遇到这个问题时,花了近两小时才找到最优解,后来通过反复练习和总结,终于形成了系统的解题思路。

2. 基础解法:双重递归分析

2.1 暴力递归思路

最直观的解法是使用双重递归:

  1. 外层递归遍历每个节点
  2. 内层递归计算以当前节点为起点的所有路径和
def pathSum(root, targetSum): if not root: return 0 def dfs(node, current_sum): if not node: return 0 current_sum += node.val count = 1 if current_sum == targetSum else 0 return count + dfs(node.left, current_sum) + dfs(node.right, current_sum) return dfs(root, 0) + pathSum(root.left, targetSum) + pathSum(root.right, targetSum)

这种解法的时间复杂度是O(n²),对于每个节点都要遍历其所有子节点。在树退化为链表的最坏情况下,性能会急剧下降。

2.2 复杂度优化思考

暴力解法的主要问题在于存在大量重复计算。比如当我们计算完节点A的所有子路径后,在计算节点A的父节点时,又会重复计算A及其子节点的路径。这种重复计算导致了不必要的性能损耗。

3. 最优解:前缀和+哈希表

3.1 前缀和概念引入

前缀和技巧通常用于数组问题,但同样适用于树结构。核心思想是:记录从根节点到当前节点的路径和,然后通过哈希表快速查找是否存在满足条件的子路径。

具体来说:

  1. 维护一个哈希表prefix_sum_count,记录路径和出现的次数
  2. 当前路径和curr_sum减去targetSum的值如果在哈希表中存在,说明存在符合条件的子路径
  3. 回溯时需要及时清理哈希表,避免影响其他路径的计算

3.2 代码实现与解析

def pathSum(root, targetSum): from collections import defaultdict prefix_sum_count = defaultdict(int) prefix_sum_count[0] = 1 # 初始状态:和为0出现1次 def dfs(node, curr_sum): if not node: return 0 curr_sum += node.val # 查找是否有满足条件的子路径 res = prefix_sum_count.get(curr_sum - targetSum, 0) # 更新当前路径和的出现次数 prefix_sum_count[curr_sum] += 1 # 递归处理左右子树 res += dfs(node.left, curr_sum) res += dfs(node.right, curr_sum) # 回溯,恢复状态 prefix_sum_count[curr_sum] -= 1 return res return dfs(root, 0)

这个算法的时间复杂度降到了O(n),因为每个节点只需要访问一次。空间复杂度主要取决于哈希表的大小和递归栈的深度,最坏情况下也是O(n)。

4. 关键细节与边界条件

4.1 哈希表初始化

prefix_sum_count[0] = 1这一初始化非常重要。它表示在路径开始前,和为0的路径已经出现过1次。这样当从根节点开始的路径和正好等于targetSum时,我们就能正确计数。

4.2 回溯处理

在递归返回前必须执行prefix_sum_count[curr_sum] -= 1,这是为了保证在计算不同分支时不会互相干扰。比如左子树计算完成后,在计算右子树时,左子树的路径和不应该被计入。

4.3 数值范围考虑

题目没有限制节点值的范围,如果节点值很大,curr_sum可能会溢出。但在Python中整数不会溢出,所以不需要特别处理。如果用其他语言实现,可能需要考虑使用长整型。

5. 测试用例设计

5.1 基础测试用例

# 用例1:简单二叉树 # 10 # / \ # 5 -3 # / \ \ # 3 2 11 # 目标值8,预期结果3

5.2 特殊边界用例

# 用例2:空树 # 目标值任意,预期结果0 # 用例3:单节点树 # 节点值5,目标值5,预期结果1 # 用例4:所有节点值相同 # 2 # / \ # 2 2 # 目标值2,预期结果3

5.3 复杂用例

# 用例5:路径和可能多次出现 # 5 # / \ # 4 8 # / / \ # 11 13 4 # / \ / \ # 7 2 5 1 # 目标值22,预期结果3

6. 常见错误与调试技巧

6.1 忘记回溯

这是最常见的错误之一。如果在递归返回前没有及时清理哈希表中的记录,会导致后续计算错误。可以通过打印哈希表内容来验证回溯是否正确。

6.2 初始化错误

忘记初始化prefix_sum_count[0] = 1会导致漏计从根节点开始的满足条件的路径。可以通过测试单节点树来验证。

6.3 路径方向混淆

题目要求路径必须是向下的,有些解法可能会错误地统计了从子节点到父节点的路径。可以通过构造不对称的树来验证。

7. 算法扩展与变种

7.1 输出所有路径

如果题目要求输出所有满足条件的路径而不仅仅是计数,我们可以修改算法,用哈希表记录路径和对应的节点列表,然后在找到满足条件的路径时,输出对应的节点序列。

7.2 路径必须从根到叶

这是路径总和问题的经典版本(LeetCode 112题)。相比本题,这个变种更简单,因为路径的起点和终点都固定了。

7.3 路径方向不限

如果取消路径必须是向下这一限制,问题会变得更加复杂,可能需要将树转换为图来处理。这种情况在实际面试中较少出现。

8. 个人刷题心得

这道题我前后做了5遍才完全掌握。最大的收获是理解了前缀和技巧不仅适用于数组,也可以灵活应用于树结构。在实际编码时,有几点特别需要注意:

  1. 画图辅助理解:对于树问题,画出具体的树结构并手动计算路径和,能帮助理解算法的执行过程。

  2. 分步验证:先实现暴力解法,确保理解题意;再逐步优化到前缀和解法,这样能更好地理解优化点在哪里。

  3. 边界测试:特别注意空树、单节点树、所有节点值相同等特殊情况,这些往往是算法出问题的地方。

  4. 回溯清理:这是最容易出错的地方,可以在递归进入和返回时打印当前状态,帮助定位问题。

经过多次练习后,我现在能在15分钟内写出无bug的前缀和解法。这道题的解题思路也帮助我解决了其他类似的问题,比如"和为K的子数组"等。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 20:57:37

GPU环境搭建指南:Anaconda、CUDA、TF2.0与Keras兼容配置

简介:一套面向深度学习入门者的环境搭建教程PPT,聚焦 Anaconda、CUDA、cuDNN、TensorFlow-gpu 与 Keras 的版本匹配和完整安装链路。PPT 从 Anaconda 下载安装讲起,逐步演示 NVIDIA 显卡驱动查看、CUDA 10.0 与 cuDNN 的下载及环境变量配置&a…

作者头像 李华
网站建设 2026/10/15 20:56:58

VST3插件开发实战:从两段式架构到process()避坑指南

简介:Steinberg官方发布的VST 3插件SDK压缩包,面向桌面与移动端音频开发者,用于在Windows、macOS、Linux和iOS平台构建音频效果器、合成器及处理工具。资源共7个文件,整体约405KB,包含txt说明、pdf协议与指南、md说明文…

作者头像 李华
网站建设 2026/10/15 20:53:54

PlanQA: A Benchmark for Spatial Reasoning in LLMs using Structured Representations

文章主要内容总结 背景与目的:现有大型语言模型(LLMs)在结构化推理方面表现出较强能力,但在物理环境中的空间推理能力仍待探索。在建筑设计、辅助规划等实际应用中,空间理解依赖JSON等结构化格式(包含物体位置、尺寸、方向等信息),而非图像或自然语言。因此,本文提出P…

作者头像 李华
网站建设 2026/10/15 20:52:56

FIR滤波器设计全攻略:从线性相位到窗函数与工程落地

1. 从一段真实经历说起:为什么 FIR 设计没那么简单我接过不少数字信号处理相关的任务,设计 FIR 滤波器算是其中出现频率最高的需求之一。很多人一开始觉得这事简单,MATLAB 里一行fir1或者 Python 里一句signal.firwin就完事了。但实际做起来&…

作者头像 李华
网站建设 2026/10/15 20:52:23

悬臂梁有限元建模与LQR主动振动控制全流程分析

悬臂梁结构在机械臂、精密仪器平台、大跨度建筑中都特别常见,它的振动控制问题可以说是结构动力学里最经典也最磨人的一个方向。很多做控制的人一开始都习惯直接写一个集中质量模型或者直接拿实验模态参数来设计控制器,但真到了工程落地阶段,…

作者头像 李华