Leetcode 二叉树 6
题号直达: 437 路径总和 III
LeetCode 437. 路径总和 III ↑
题目
给定一个二叉树的根节点 root 和一个整数 targetSum,求该二叉树里结点值之和等于 targetSum 的路径的数目。
路径不需要从根结点开始,也不需要在叶结点结束,但路径方向必须是向下的(只能从父结点到子结点)。
提示
- 二叉树的结点数在范围
[0, 1000]内 -10^9 ≤ Node.val ≤ 10^9-1000 ≤ targetSum ≤ 1000
示例图

代码(Python)解法一:BFS 枚举起点 + DFS 统计路径
对每个结点作为路径起点,向下 DFS,用「剩余目标和」targetSum - p.val 递归;当前结点若恰好等于剩余目标和则计数 +1。
from collections import deque
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def __init__(self):
self.num = 0
def rootSum(self, p, targetSum):
if not p:
return 0
count = 1 if p.val == targetSum else 0
count += self.rootSum(p.left, targetSum - p.val)
count += self.rootSum(p.right, targetSum - p.val)
return count
def pathSum(self, root, targetSum):
if not root:
return 0
temp = deque()
temp.append(root)
self.num = 0
while temp:
p = temp.popleft()
self.num += self.rootSum(p, targetSum)
if p.left:
temp.append(p.left)
if p.right:
temp.append(p.right)
return self.num
思路解析(解法一)
- 外层 BFS:队列遍历每一个结点,将其视为路径起点,避免漏数「不以根为起点」的路径。
- 内层
rootSum(p, targetSum):从结点p出发,只向下走;若p.val == targetSum则当前路径算一条;再在左右子树中继续找和为targetSum - p.val的路径条数并累加。 self.num:对每个起点累加rootSum的返回值;每次pathSum入口将self.num置 0,避免多次调用时残留。- 复杂度:每个起点做一次 DFS,最坏 O(n) 层递归深度,整体最坏约 O(n²),在
n ≤ 1000下可接受;存在 前缀和 + 哈希 的 O(n) 做法,可作进阶。
代码(Python)解法二:前缀和 + 哈希表(一次 DFS,O(n))
说明(个人备注):第二种方法(前缀和 + 哈希)尚未理解透彻,先存档代码与注释;日后可对照题解或视频再啃。
从根到当前结点有一条自上而下的路径,记路径和为 curr。
若某段路径和为 targetSum,等价于存在祖先侧前缀和 p,使 curr - p = targetSum,即查 prefix[curr - targetSum]。
哈希表记录当前 DFS 链上各前缀和出现次数;入子树 +1,回溯 -1。
from collections import defaultdict
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def pathSum(self, root, targetSum):
# prefix[s]:当前 DFS 链上,前缀和 s 出现次数
prefix = defaultdict(int)
# 前缀和 0 计 1 次:整段路径和恰为 targetSum 时
# 对应「减去空前缀」的一种情况
prefix[0] = 1
def dfs(root, curr):
# root:当前子树根
# curr:进入本结点前,从根到父结点的路径和
if not root:
return 0
ret = 0
# 加上本结点值,得到根到当前结点的路径和
curr = curr + root.val
# 以当前结点为终点的合法路径数:
# 已有多少前缀和为 curr - targetSum
ret = ret + prefix[curr - targetSum]
# 当前结点作为前缀终点,curr 计数 +1,供子树用
prefix[curr] += 1
# 左子树
ret += dfs(root.left, curr)
# 右子树
ret += dfs(root.right, curr)
# 回溯:离开本结点,撤销 prefix[curr]
# 避免兄弟子树误用本分支计数
prefix[curr] -= 1
return ret
return dfs(root, 0)
思路解析(解法二)
- 核心等式:根到
v的路径和为curr(v)。若从某祖先下一结点到v的和为targetSum,则curr(v) - curr(u) = targetSum,即curr(u) = curr(v) - targetSum。
用prefix[curr - targetSum]统计路径上此前出现过几次该前缀和。 prefix[0] = 1:当curr == targetSum时,需要prefix[0]为 1,对应从根到当前整段一条路径。- 回溯
prefix[curr] -= 1:返回父层前撤销当前结点对哈希的贡献,否则兄弟子树会串台。 - 与解法一:每个结点只访问一次,时间 O(n),哈希 O(n)。

浙公网安备 33010602011771号