给定一个二叉树,它的每个结点都存放着一个整数值。
找出路径和等于给定数值的路径总数。
路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。
示例:
root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8
10
/ \
5 -3
/ \ \
3 2 11
/ \ \
3 -2 1
返回 3。和等于 8 的路径有:
1. 5 -> 3
2. 5 -> 2 -> 1
3. -3 -> 11
解题思路
这个问题非常有意思。和之前问题
Leetcode 112:路径总和(最详细的解法!!!)
Leetcode 113:路径总和 II(最详细的解法!!!)
的区别在于,这个问题不一定是从根节点出发。知道这一点的话,我们很容易写出
def pathSum(self, root, sum):
"""
:type root: TreeNode
:type sum: int
:rtype: int
"""
result = 0
if not root:
return result
result += self.findPath(root, sum)
result += self.pathSum(root.left, sum)
result += self.pathSum(root.right, sum)
return result
这里我们一定要明确findPath
和pathSum
的区别。findPath
的含义就是查找包含root
并且和为sum
的路径个数。而pathSum
是查找不一定包含root
并且和为sum
的路径个数。也就是含义上pathSum
包括了findPath
。那么我们能不能使用pathSum
替代findPath
呢?显然不行。而findPath
,我们在前面就写过很多次,不再赘述。
class Solution:
def findPath(self, root, sum):
result = 0
if not root:
return result
if root.val == sum:
result += 1
result += self.findPath(root.left, sum - root.val)
result += self.findPath(root.right, sum - root.val)
return result
def pathSum(self, root, sum):
"""
:type root: TreeNode
:type sum: int
:rtype: int
"""
result = 0
if not root:
return result
result += self.findPath(root, sum)
result += self.pathSum(root.left, sum)
result += self.pathSum(root.right, sum)
return result
你可能已经发现了,上面的解法是一种暴力破解,这种做法中存在着大量的重复运算。我们对这个问题进行优化,其中我们主要用到这样的一个性质:curSum - sum = oldSum
,oldSum
就是我们要记录的。
用题目的例子来说
10
/ \
5 -3
/ \ \
->3 2 11
/ \ \
3 -2 1
当我们遍历到3
,我们此时目标是sum=8
,我们这个时候不一定要向下找,可以向上找sum=8
的路径。我们此时知道从root
到3
这个节点的sum=18
,那么这个时候我们只要知道从根节点开始到3
这个节点的路径上有没有sum=10
的路径就可以了。而sum=10
的这个路径,我们可以在向下遍历的过程中,通过一个map
记录。这里我们默认情况下,和的个数为0
,所以我们要用到collections.defaultdict
。
import collections
class Solution:
def pathSum(self, root, sum):
"""
:type root: TreeNode
:type sum: int
:rtype: int
"""
if not root:
return 0
self.result = 0
freq = collections.defaultdict(int)
freq[0] = 1
self.dfs(root, 0, freq, sum)
return self.result
def dfs(self, node, pathSum, freq, sum):
if node:
pathSum += node.val
self.result += freq[pathSum - sum]
freq[pathSum] += 1
self.dfs(node.left, pathSum, freq, sum)
self.dfs(node.right, pathSum, freq, sum)
freq[pathSum] -= 1
我们的这些优化居然打出了暴击,从原先的1464ms
变成了56ms
,超越了100%
的用户。
我将该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!