Given the root
of a binary tree and an integer targetSum
, return the number of paths where the sum of the values along the path equals targetSum
.
The path does not need to start or end at the root or a leaf, but it must go downwards (i.e., traveling only from parent nodes to child nodes).
Example 1:
Input: root = [10,5,-3,3,2,null,11,3,-2,null,1], targetSum = 8 Output: 3 Explanation: The paths that sum to 8 are shown.
Example 2:
Input: root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22 Output: 3
Constraints:
[0, 1000]
.-109 <= Node.val <= 109
-1000 <= targetSum <= 1000
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach involves exploring every single path in the tree to see if it sums up to the target value. We essentially check all possible starting points and then try all possible paths downwards from those points. This ensures no possible combination is missed, guaranteeing we find all valid paths, even if inefficiently.
Here's how the algorithm would work step-by-step:
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def path_sum_brute_force(root, target_sum):
number_of_paths = 0
def path_sum_from_node(node, current_sum):
nonlocal number_of_paths
if not node:
return
# Check if the current node's value equals the target
if node.val == current_sum:
number_of_paths += 1
# Explore the left and right subtrees
path_sum_from_node(node.left, current_sum - node.val)
path_sum_from_node(node.right, current_sum - node.val)
def traverse_tree(node):
nonlocal number_of_paths
if not node:
return
# Consider each node as a potential starting point
path_sum_from_node(node, target_sum)
# Recursively check subtrees
traverse_tree(node.left)
traverse_tree(node.right)
# Start traversal from the root
traverse_tree(root)
return number_of_paths
The efficient approach to this tree problem involves clever use of previous information to avoid redundant calculations. It uses a 'prefix sum' strategy combined with a data structure to remember past sums, allowing us to quickly identify paths that meet the target sum.
Here's how the algorithm would work step-by-step:
def pathSum(root, targetSum): def traverseTree(node, currentSum, prefixSums, pathCount): if not node: return pathCount currentSum += node.val
# Check if there's a path ending at the current node with the target sum
difference = currentSum - targetSum
pathCount += prefixSums.get(difference, 0)
# Update the prefix sums count
prefixSums[currentSum] = prefixSums.get(currentSum, 0) + 1
pathCount = traverseTree(node.left, currentSum, prefixSums, pathCount)
pathCount = traverseTree(node.right, currentSum, prefixSums, pathCount)
# Backtrack: remove the current sum from the prefix sums
prefixSums[currentSum] -= 1 return pathCount # Initialize prefix sums with 0 to account for paths starting at root
prefixSums = {0: 1}
return traverseTree(root, 0, prefixSums, 0)
Case | How to Handle |
---|---|
Null root | Return 0 immediately as there are no paths in an empty tree. |
Single node tree where node value equals targetSum | Return 1 as the single node forms a valid path. |
All node values are zero and targetSum is zero | The number of paths should be counted correctly, considering all possible downward paths. |
Tree with many negative numbers and a negative targetSum | The solution must correctly handle negative prefixes and target values during path traversal. |
Tree with a deep and skewed structure (e.g., linked list) | Ensure the recursion depth does not exceed limits and the time complexity remains reasonable (e.g., O(n) space for prefix sums). |
TargetSum is a very large number potentially leading to integer overflow if node values are large | Use long data type to store running sums to avoid overflow. |
Tree with extreme boundary node values near max/min integer limits | Ensure the solution handles extreme values correctly without causing unexpected behavior due to integer limits. |
Multiple valid paths exist summing to the targetSum | The algorithm should count *all* valid paths, not just the first one found. |