Path Sum II

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, not node references.

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]]

Explanation: There are two paths whose sum equals targetSum:

5 + 4 + 11 + 2 = 22

5 + 8 + 4 + 5 = 22

Example 2:

Input: root = [1,2,3], targetSum = 5

Output: []

Example 3:

Input: root = [1,2], targetSum = 0

Output: []

Constraints:

  • The number of nodes in the tree is in the range [0, 5000].
  • -1000 <= Node.val <= 1000
  • -1000 <= targetSum <= 1000

Solution

We wish to fill in the template logic:

  • is_leaf: when node is a leaf in the tree, and there is no remaining left.
  • get_edges: the children of the current node (node.left and node.right).
  • is_valid: an edge (node) is only invalid when it is non-empty (None, null).

In the implementation, we want to check whether node is None first, so that we do not try to get the field of an empty object. On the current node, we calculate the remaining value after adding the current value. Then we check whether the node is a leaf so that path is a root-to-leaf path and whether the remaining value left is 0. If these condition is satisfied, then we have found one solution. If not, we'd have to traverse further until we reach a leaf in the tree (may or may not be a solution).

The below implementation may look different than the template, but essentially one can update and revert path and remaining inside the if-else conditions to gain similarity to the template. We had also left the check of node is None on the outside to accommodate the use of node.val (and to prevent the root being empty).

Implementation

def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
    def dfs(node, remaining, path):
        if (node is None): return
        path.append(node.val)     # update path
        remaining -= node.val
        if node.left is None and node.right is None and remaining == 0: # is_leaf
            paths.append(path[:])
        else:     # edges = [node.left, node.right]
            dfs(node.left, remaining, path)
            dfs(node.right, remaining, path)
        path.pop()                # revert path

    paths = []
    dfs(root, targetSum, [])
    return paths

Ready to land your dream job?

Unlock your dream job with a 2-minute evaluator for a personalized learning plan!

Start Evaluator
Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:
Question 1 out of 10

You are given an array of intervals where intervals[i] = [start_i, end_i] represent the start and end of the ith interval. You need to merge all overlapping intervals and return an array of the non-overlapping intervals that cover all the intervals in the input.


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!