Given the root
of a binary tree and an integer targetSum
, return all root-to-leaf paths where the sum of the node values in the path equals targetSum
. Each path should be returned as a list of the node values.
A root-to-leaf path is a path starting from the root and ending at any leaf node. A leaf is a node with no children.
Example 1:
Input: root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
Output: [[5,4,11,2],[5,8,4,5]]
Example 2:
Input: root = [1,2,3], targetSum = 5
Output: []
Example 3:
Input: root = [1,2], targetSum = 0
Output: []
Explain your approach. Discuss time and space complexity. What are some edge cases to consider?
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 method for the path sum problem involves exploring every possible path from the root of a tree to its leaves. We examine each path's sum to see if it matches the target sum, recording any paths that do. This method is exhaustive, guaranteeing that we find all valid paths.
Here's how the algorithm would work step-by-step:
class TreeNode:
def __init__(self, value=0, left=None, right=None):
self.value = value
self.left = left
self.right = right
def pathSumBruteForce(root, target_sum):
all_valid_paths = []
current_path = []
def explore_paths(node, current_sum):
if not node:
return
# Add the current node's value to the path
current_path.append(node.value)
current_sum += node.value
# Check if it is a leaf node
if not node.left and not node.right:
if current_sum == target_sum:
all_valid_paths.append(current_path[:])
else:
# Recursively explore the left and right subtrees
explore_paths(node.left, current_sum)
explore_paths(node.right, current_sum)
# Backtrack: Remove the current node from the path
current_sum -= current_path[-1]
current_path.pop()
explore_paths(root, 0)
return all_valid_paths
The goal is to find all paths from the root of a tree to its leaves where the sum of the node values along the path equals a target value. We'll use a clever way to explore each path and keep track of the current sum as we go, avoiding unnecessary calculations.
Here's how the algorithm would work step-by-step:
class TreeNode:
def __init__(self, value=0, left=None, right=None):
self.value = value
self.left = left
self.right = right
def pathSum(root, target_sum):
all_valid_paths = []
current_path = []
def traverseTree(node, current_sum):
if not node:
return
current_path.append(node.value)
current_sum += node.value
# Check if the current node is a leaf node.
if not node.left and not node.right:
# If leaf node and current sum equals target sum,
# then add the current path to result.
if current_sum == target_sum:
all_valid_paths.append(current_path[:])
else:
# Recursively traverse left and right subtrees.
traverseTree(node.left, current_sum)
traverseTree(node.right, current_sum)
# Backtrack: remove current node and subtract
# its value when returning to the parent node.
current_sum -= node.value
current_path.pop()
# Initiate traversal from the root node.
traverseTree(root, 0)
return all_valid_paths
Case | How to Handle |
---|---|
Null root node | Return an empty list immediately as there are no paths. |
Single node tree where node value equals targetSum | Return a list containing a list with the single node's value. |
Single node tree where node value does NOT equal targetSum | Return an empty list as no path satisfies the condition. |
Tree with only negative values and a negative targetSum | The algorithm should correctly traverse and identify paths that sum to the (negative) target. |
Tree with large positive and negative values leading to potential integer overflow when summing the path | Use a data type (e.g., long) that can accommodate the larger potential sums to prevent overflow issues. |
Tree with a path that sums to targetSum but is not a root-to-leaf path | Ensure the path ends at a leaf node (left and right children are null) to be considered a valid solution. |
Multiple root-to-leaf paths that sum to targetSum | The solution must identify and store all such paths in the result list. |
Deeply unbalanced tree potentially leading to stack overflow with recursion | While recursion is a common approach, be mindful of stack depth; iterative solutions with explicit stack management could prevent stack overflow in extremely deep trees. |