在问 · 算法题解

113. 路径总和 II

中等二叉树回溯(深度优先搜索)力扣原题 ↗

题目描述

输入二叉树的根节点 root 和一个整数 targetSum。

找出所有从根出发、到某个叶子节点结束,并且节点值之和等于 targetSum 的路径。叶子节点指没有孩子的节点。

每条路径写成从根到叶子依次经过的节点值列表。返回由这些路径组成的列表;一条都没有时返回 []。树用层序数组表示,null 代表空位。

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

解释:5+4+11+2 与 5+8+4+5 都等于 22。

示例 2
输入:root = [1,2,3], targetSum = 5
输出:[]

解释:根到叶子的路径和只有 3 和 4。

示例 3
输入:root = [1,2], targetSum = 0
输出:[]

解释:唯一的根到叶子路径 1 -> 2 和为 3,不等于 0。

数据范围

  • 节点总数在 [0, 5000] 之间。
  • -1000 <= Node.val <= 1000
  • -1000 <= targetSum <= 1000

解题思路:回溯(深度优先搜索)

深度优先搜索加回溯。用一个 path 列表记录从根到当前节点的路径,进入节点时 append,离开时 pop。同时把剩余值 rest 往下传,到达叶子且 rest 为 0 时,把 path 的一份拷贝加入结果。

为什么正确

进入 dfs(node, rest) 时,path 恰好是根到 node 父节点的路径,rest 等于 targetSum 减去 path 中各值之和。

复杂度分析

时间 O(n^2)(最坏每个叶子都要拷贝长为 O(n) 的路径),空间 O(h) 不计结果。

易错点

加入结果时必须拷贝 path(path[:]),否则之后的 pop 会把结果里的列表一起改掉。离开节点前别忘了 path.pop()。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        res, path = [], []
        def dfs(node, rest):
            if not node:
                return
            path.append(node.val)
            rest -= node.val
            if not node.left and not node.right and rest == 0:
                res.append(path[:])
            dfs(node.left, rest)
            dfs(node.right, rest)
            path.pop()
        dfs(root, targetSum)
        return res

载入编辑器,自己跑一遍 →

其他解法

回溯用一条共享路径边走边恢复,最简洁;广度优先搜索只在命中时沿父指针还原路径,适合不想递归的场景。

解法 2:广度优先搜索 + 父指针 时间 O(n²),空间 O(n)

队列里保存节点和到它为止的路径和,并用哈希表记录每个节点的父节点。遇到路径和等于 targetSum 的叶子时,沿父指针走回根得到路径,再反转加入结果。

没有递归,深链树不会栈溢出。要多存一张父节点表,代码比回溯长。

from collections import deque

class Solution:
    def pathSum(self, root, targetSum):
        res = []
        if not root:
            return res
        parent = {root: None}
        queue = deque([(root, root.val)])
        while queue:
            node, s = queue.popleft()
            if not node.left and not node.right:
                if s == targetSum:
                    path = []
                    cur = node
                    while cur:
                        path.append(cur.val)
                        cur = parent[cur]
                    res.append(path[::-1])
                continue
            for child in (node.left, node.right):
                if child:
                    parent[child] = node
                    queue.append((child, s + child.val))
        return res

二叉树 专题的其他题目

查看 二叉树 全部题目 →