题目描述
You are given a binary tree in which each node contains an integer value.
Find the number of paths that sum to a given value.
The path does not need to start or end at the root or a leaf, but it must go downwards (traveling only from parent nodes to child nodes).
The tree has no more than 1,000 nodes and the values are in the range -1,000,000 to 1,000,000.
Example:
root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8
10
/ \
5 -3
/ \ \
3 2 11
/ \ \
3 -2 1
Return 3. The paths that sum to 8 are:
1. 5 -> 3
2. 5 -> 2 -> 1
3. -3 -> 11
方法一:暴力破解
采用先根次序遍历整棵树,递归寻找符合目标的路径个数,时间复杂度是O(N**2)。
如果是平衡二叉树(Balanced Binary Tree,具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。),则所需要的时间T(N) = N + 2T(N/2),即归并排序递归的复杂度 NlgN。
class SolutionBruteForce(object):
def find_paths(self, root, target):
if root:
return int(root.val == target) + self.find_paths(root.left, target-root.val) + self.find_paths(root.right, target-root.val)
return 0
def pathSum(self, root, sum):
"""
:type root: TreeNode
:type sum: int
:rtype: int
"""
if root:
return self.find_paths(root, sum) + self.pathSum(root.left, sum) + self.pathSum(root.right, sum)
方法二:最优解
- 使用两个和的方法,使用一个hash表,增加了额外的空间复杂度O(N);
- 随着我们从根开始向下遍历树,在任意一个节点N,在hash表中保存直到节点N的和(sum_so_far(prefix)+N.val),该sum是根到N的和;
- 在N的子孙节点G处,由于已经保存了根到G的路径的前缀和,所以可以计算出根到G的路径和,进入递归过程;
- 如何知道是否有一个以G为终点的满足目标的路径和呢?假设有多条这样的路径以G结尾,并且说它们从A,B,C开始,其中A,B,C是G的祖先,sum(root-> G)- sum(root-> A)= target。 类似地,sum(root-> G)-sum(root-> B)=target。 因此,我们可以将G中的补数(要达成target仍需要的数)计算为sum_so_far + G.val-target,并查找哈希表中具有该总和的路径数量;
- 当我们完成一个节点和它的所有子孙时,将它从hash表中移除,确保了返回的满足补数路径的数量总是对应于以祖先节点结束的路径。
class Solution(object):
def helper(self, root, target, so_far, cache):
if root:
complement = so_far + root.val - target #定义补数
if complement in cache: #在hash表中寻找是否存在补数
self.result += cache[complement] #更新答案
cache.setdefault(so_far+root.val, 0) #将从根到当前节点的路径和加入hash表
cache[so_far+root.val] += 1 #更新当前路径和的值(个数)
self.helper(root.left, target, so_far+root.val, cache) #递归遍历左子树
self.helper(root.right, target, so_far+root.val, cache) #递归遍历右子树
cache[so_far+root.val] -= 1 #处理完后,移除根到该节点的路径和
return
def pathSum(self, root, sum):
"""
:type root: TreeNode
:type sum: int
:rtype: int
"""
self.result = 0
self.helper(root, sum, 0, {0:1})
return self.result
简洁的方法
定义一个子方法 SumUP,计算以当前结点为起点,和为 sum 的路径个数。
递归调用该方法与pathSum方法。
pathSum:求所有和为sum的路径个数,不规定起点,起点可以是任意节点。
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def pathSum(self, root, sum):
"""
:type root: TreeNode
:type sum: int
:rtype: int
"""
if root is None:
return 0
return self.SumUp(root, 0, sum) + self.pathSum(root.left, sum) + self.pathSum(root.right, sum)
def SumUp(self, node, pre, sum):
if node is None:
return 0
cur = node.val + pre
return (cur == sum) + self.SumUp(node.left, cur, sum) + self.SumUp(node.right, cur, sum)