Leetcode刷题——437. 路径总和Ⅲ

一、原题链接

  [437.路径总和Ⅲ](https://leetcode-cn.com/problems/path-sum-iii/)

在这里插入图片描述

二、解题思路

  总体而言,解这道题目是利用前缀和的思想。所谓前缀和,就是指在一条路径上的有某个元素A,A之前所有元素的和(包括A),称之为前缀和。
  路径上存在元素A和B(A和B有前后关系),如果A和B的前缀和相等,那么我们可以推测出A、B之间的元素和为0;如果元素B的前缀和比A的前缀和多sum,则说明A、B之间的元素和为sum。

   1、用栈迭代处理

  利用栈来实现前缀遍历,栈中元素为元组(node,prefixsum),其中prefixsum是一个列表,记录从根结点到达当前结点node的前缀和。
  为了简单说明,以结点的值代表结点。 初始化栈为(10,[10]);弹出栈顶元素,访问其左子结点,并将(5,[15, 5])入栈,访问其右子结点,将(-3,[7,-3])入栈……

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None


class Solution:
    def pathSum(self, root: TreeNode, sum: int) -> int:
        if not root:
           return 0
        stack = [(root, [root.val])]
        cnt = 0   #  记录路径和
        while stack:
            node, prefix_sum = stack.pop()
            cnt += prefix_sum.count(sum)
            prefix_sum.append(0)
            if node.left:
                #  更新前缀和
                tmp = [val+node.left.val for val in prefix_sum]
                # 左子结点入栈
                stack.append((node.left, tmp))
            if node.right:
                tmp = [val+node.right.val for val in prefix_sum]
                stack.append((node.right, tmp))
        return cnt

   2、递归处理

  同样是基于前缀和以及前缀和哈希表,不过利用递归来实现。 有一点需要注意,一定要将前缀和哈希表初始化为{0:1}而不是初始化为空。考虑下图所示情况,sum为22:

在这里插入图片描述

  如果初始化哈希表为空,递归从根结点开始:
  根结点5:哈希表更新为{5:1};
  左子结点4:哈希表更新为{5:1, 9:1};
  左子结点11:哈希表更新为{5:1,9:1,20:1};
  左子结点7:此时的前缀和为20+7=27,27-22=5,哈希表中存在前缀和为5的项,因此找到一条和为22的路径,将count加1,同时哈希表更新为{5:1, 9:1, 20:1, 27:1};
  此时,结点7为叶子结点,树的最左分支处理完毕,要回溯处理结点11的右子结点,因此,在退回之前,应该将哈希表中key值为27的项的value-1,哈希表更新为{5:1, 9:1, 20:1, 27:0};
  右子结点2:此时前缀和为20+2=22,但是在哈希表初始化为空的情况下不存在key为0的项,因此也就不记录这一条路径!因此需要将哈希表初始化为{0:1}。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None


class Solution:
    def pathSum(self, root: TreeNode, sum: int) -> int:
        self.count = 0   # 记录符合条件的路径数目
        prefixSumArray = {0:1}   # 初始化前缀和哈希表为{0:1}
        prefixSum = 0   # 记录当前结点的前缀和
        self.dfs(root, sum, prefixSumArray, prefixSum)  # 深搜处理
        return self.count


    def dfs(self, root, sum, prefixSumArray, prefixSum):
        #  结点如果是None,返回
        if not root:
            return 0
        # 更新前缀和,加上当前结点的val
        prefixSum += root.val
        #  查看哈希表中是否存在和为sum的路径,存在的话更新count
        self.count += prefixSumArray.get(prefixSum-sum, 0)
        #  将当前的前缀和记录到哈希表中
        prefixSumArray[prefixSum] = prefixSumArray.get(prefixSum, 0) + 1

        #  遍历处理左子树和右子树
        self.dfs(root.left, sum, prefixSumArray, prefixSum)
        self.dfs(root.right, sum, prefixSumArray, prefixSum)

        #  处理完子树回退之前,记得要将对应前缀和的value值减一,如上述绿色文字所示。
        prefixSumArray[prefixSum] -= 1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值