437. 路径总和 III(前缀和法)

437. 路径总和 III

前缀和的概念

1、所谓前缀和,就是求从根节点到当前节点所经过的所有节点的和。设根节点的为root,当前节点为node5,从root到node5依次进过了node2,node3,node4,则node5的前缀和为root+node2+node3+node4+node5。其他的节点以此类推。

2、当求是否存在路径总和为target时,以target为8举例子,假设node2的前缀和为2,node5的前缀和为10,则可以断定node3+node4+node5的路径总和为8。

深度优先搜索:先序遍历

1、因为前缀和是从根节点到当前节点所经过的所有节点的和,即我们要遍历同一个路径的上的节点,因此应使用深度优先搜索来遍历节点。

2、又因为前缀和是从根节点到当前节点所经过的所有节点的和,要求每次要加上本节点的和,因此要先拿到本节点的值,再遍历本节点的子节点。这就是所谓前序遍历,又叫先序遍历,即根在前,然后左右子节点。

        综上,我们在求某个节点的前缀和时,应使用前序遍历,将这个节点之前的所有节点的值加起来,成为这个节点的前缀和。

哈希表:记录前缀和、降低复杂度 O(1)

1、接下来,继续以是否存在路径总和为target时,以target为8举例子,假设node2的前缀和为2,node5的前缀和为10,则可以断定node3+node4+node5的路径总和为8。当我们求导node5的前缀和时,我们必须要知道它之前的节点有没有一个前缀和为2的节点。这就需要有一个备忘录,显然字典是备忘录的首选。因此,我们要定义一个字典,用来存储每个节点及它之前的节点的前缀和。

2、我们只关心有没有符合要求的前缀和就行了。即当node5的前缀和是10时,我们只需要知道在node5之前的节点里,有没有前缀和为2的节点就行了,至于这个前缀和为2的节点距离node5有多远,经过了哪几个节点,不关心。因此字典里,只需要呈现前缀和为2的节点,有还是没有。那么,我们是否要求知道前缀和为2的节点有几个呢?我理解是需要的。因为题目里并没有说节点的值都是正值,因此节点里可能有负值。假设node2的前缀和为2,node3的值(非前缀和)为3,node4的值(非前缀和)为-3,那么node4的前缀和也为2.此时,若node5的前缀和为10,则如果字典里显示前缀和为2的节点有2个,则我们可以知道截止到node5,存在2个路径之和为8.
因此,该字典的键为出现的前缀和,值为这个前缀和出现的次数。

节点的前缀和只与其子树有关,子树遍历之后需要删除该节点的前缀和

继续以以当求是否存在路径总和为target时,以target为8举例子,假设node2的前缀和为2,node5的前缀和为10,则可以断定node3+node4+node5的路径总和为8为例子。假设有一个node10的前缀和也是10,但是node10压根不和node2~4在一个路径上,那node10是不能用node2的前缀和的。那么,该如何避免这种情况呢?那就是当node2的左右两个子树均搜索完毕后,应在字典里,将前缀和为2的数量减去1。为什么呢?因为node2的前缀和只能为它的子树所用,其他的树节点不能用node2的前缀和。因此在搜索完node2的左右子树后,要在字典里把node2的前缀和对应的值减去1.
 

class Solution:
    def pathSum(self, root: TreeNode, targetSum: int) -> int:
        prefix = collections.defaultdict(int)
        # 这里的prefix[0] = 1是为了计算某些单个节点就直接为target的情况
        prefix[0] = 1
        def dfs(root, curr):
            if not root:
                return 0
            ret = 0
            curr += root.val
            # 判断字典中有没有符合条件的前缀和
            ret += prefix[curr - targetSum] 
            # 有相同则累加,没有则赋值为1
            prefix[curr] += 1
            ret += dfs(root.left, curr)
            ret += dfs(root.right, curr)
            # 当前root遍历后回溯需要-1,保证该节点的前缀和只能用于该节点的子树
            prefix[curr] -= 1
            return ret
        return dfs(root, 0)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值