Talentd
FleetCode
Make and follow sheets.Sign in

Path Sum II solution and explanation

MediumBacktrackingBinary TreeDepth-First SearchTree6 min read62.6% acceptanceUpdated 9 Apr 2026
Path Sum II - LeetCode 113 PythonDeepti Talesra · 9:13 · 7K viewsWatch on YouTube
9 more videos on this problem
  1. Path Sum II - LeetCode 113 PythonDeepti Talesra · 9:13 · 7K views
  2. Leetcode - Path Sum II (Python)Timothy H Chang · 4:46 · 6K views
  3. LEETCODE 113 (JAVASCRIPT) | PATH SUM IIAndy Gala · 12:56 · 3K views
  4. [Java] Leetcode 113. Path Sum II [Binary Tree #13]Eric Programming · 8:44 · 2K views
  5. Path Sum II - LeetCode 113 - JavaScriptAlgoJS · 7:31 · 1K views
  6. Solving LeetCode 113 in JavaScript (Path Sum II)KA Education · 5:20 · 1K views
  7. Path Sum II - LeetCode 113 - JavaScriptAlgoJS · 8:15 · 946 views
  8. Path Sum II | LeetCode 113 | Coders CampCoders Camp · 7:15 · 626 views
  9. LeetCode - 113. Path Sum II | DFS | JavaOrkhan Gasanov · 11:15 · 406 views
  10. Leetcode 113: Path Sum II | Master Trees | Intuition and ApproachCode Concepts with Animesh · 15:20 · 401 views

The problem

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

Approach overview

Problem Overview: Given a binary tree and a target sum, return all root-to-leaf paths where the sum of node values equals the target. A path must start at the root and end at a leaf node, and you need to return every valid path.

Approach 1: Recursive Depth-First Search with Backtracking (O(n) time, O(h) space)

This approach performs a depth-first traversal from the root while maintaining the current path and remaining sum. At each node, append the node value to the path and subtract it from the remaining target. When a leaf node is reached and the remaining sum becomes zero, copy the current path into the result list. Backtracking is critical: after exploring a node’s children, remove the node from the path so the same list can be reused for other branches. Each node is visited once, giving O(n) traversal time where n is the number of nodes, while the recursion stack uses O(h) space where h is the tree height. This technique combines depth-first search with backtracking to efficiently explore every root-to-leaf path.

Approach 2: Iterative DFS with Stack (O(n) time, O(h) space)

An iterative variant replaces recursion with an explicit stack. Each stack entry stores the current node, the remaining sum, and the path taken so far. Start by pushing the root node and its value. Pop nodes from the stack, update the path and remaining sum, and push child nodes with updated state. When a leaf node is encountered and the remaining sum equals the node value, add the path to the result list. The traversal order still mimics DFS but avoids recursion, which can be helpful in environments with limited recursion depth. The algorithm still visits every node once, resulting in O(n) time complexity and O(h) auxiliary space for the stack in a balanced binary tree.

Recommended for interviews: Recursive DFS with backtracking is the expected solution. Interviewers want to see that you can track a path, update a running sum, and undo state changes when returning from recursion. The iterative stack version demonstrates deeper understanding of DFS mechanics, but the recursive version is usually faster to implement and easier to reason about during an interview.

Approach 1: Recursive Depth-First Search

Using a recursive DFS, traverse each path from root to leaf, maintaining the current path and its corresponding sum. When a leaf is reached, check if the path's sum matches the targetSum. Use backtracking to explore all paths.

from typing import List, Optional

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        def dfs(node, current_sum, path):
            if not node:
                return
            current_sum += node.val
            path.append(node.val)
            if not node.left and not node.right and current_sum == targetSum:
                result.append(list(path))
            else:
                dfs(node.left, current_sum, path)
                dfs(node.right, current_sum, path)
            path.pop()

        result = []
        dfs(root, 0, [])
        return result
import java.util.ArrayList;
import java.util.List;

public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode() {}
    TreeNode(int val) { this.val = val; }
    TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

class Solution {
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        List<List<Integer>> result = new ArrayList<>();
        List<Integer> path = new ArrayList<>();
        dfs(root, targetSum, path, result);
        return result;
    }
    private void dfs(TreeNode node, int sum, List<Integer> path, List<List<Integer>> result) {
        if (node == null) return;
        path.add(node.val);
        if (node.left == null && node.right == null && sum == node.val) {
            result.add(new ArrayList<>(path));
        } else {
            dfs(node.left, sum - node.val, path, result);
            dfs(node.right, sum - node.val, path, result);
        }
        path.remove(path.size() - 1);
    }
}
#include <vector>
using namespace std;

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};

class Solution {
public:
    void dfs(TreeNode* root, int targetSum, vector<int>& path, vector<vector<int>>& result) {
        if (!root) return;
        path.push_back(root->val);
        targetSum -= root->val;
        if (!root->left && !root->right && targetSum == 0) {
            result.push_back(path);
        } else {
            dfs(root->left, targetSum, path, result);
            dfs(root->right, targetSum, path, result);
        }
        path.pop_back();
    }
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        vector<vector<int>> result;
        vector<int> path;
        dfs(root, targetSum, path, result);
        return result;
    }
};
function TreeNode(val, left, right) {
    this.val = (val===undefined ? 0 : val);
    this.left = (left===undefined ? null : left);
    this.right = (right===undefined ? null : right);
}

var pathSum = function(root, targetSum) {
    const result = [];
    const path = [];
    const dfs = (node, currentSum) => {
        if (!node) return;
        currentSum += node.val;
        path.push(node.val);
        if (!node.left && !node.right && currentSum === targetSum) {
            result.push([...path]);
        } else {
            dfs(node.left, currentSum);
            dfs(node.right, currentSum);
        }
        path.pop();
    };
    dfs(root, 0);
    return result;
};
#include <stdio.h>
#include <stdlib.h>

struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
};

void dfs(struct TreeNode* root, int targetSum, int currentSum, int* path, int pathIndex, int** result, int* returnSize, int** columnSizes) {
    if (!root) return;
    currentSum += root->val;
    path[pathIndex++] = root->val;
    if (!root->left && !root->right && currentSum == targetSum) {
        result[*returnSize] = (int*)malloc(pathIndex * sizeof(int));
        columnSizes[0][*returnSize] = pathIndex;
        for (int i = 0; i < pathIndex; ++i) {
            result[*returnSize][i] = path[i];
        }
        (*returnSize)++;
    } else {
        dfs(root->left, targetSum, currentSum, path, pathIndex, result, returnSize, columnSizes);
        dfs(root->right, targetSum, currentSum, path, pathIndex, result, returnSize, columnSizes);
    }
}

int** pathSum(struct TreeNode* root, int targetSum, int* returnSize, int** columnSizes) {
    *returnSize = 0;
    int** result = (int**)malloc(1000 * sizeof(int*));
    *columnSizes = (int*)malloc(1000 * sizeof(int));
    int* path = (int*)malloc(1000 * sizeof(int));
    dfs(root, targetSum, 0, path, 0, result, returnSize, columnSizes);
    free(path);
    return result;
}
using System.Collections.Generic;

public class TreeNode {
    public int val;
    public TreeNode left;
    public TreeNode right;
    public TreeNode(int val=0, TreeNode left=null, TreeNode right=null) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

public class Solution {
    public IList<IList<int>> PathSum(TreeNode root, int targetSum) {
        IList<IList<int>> result = new List<IList<int>>();
        List<int> path = new List<int>();
        Dfs(root, targetSum, path, result);
        return result;
    }

    private void Dfs(TreeNode node, int sum, List<int> path, IList<IList<int>> result) {
        if (node == null) return;
        path.Add(node.val);
        if (node.left == null && node.right == null && sum == node.val) {
            result.Add(new List<int>(path));
        } else {
            Dfs(node.left, sum - node.val, path, result);
            Dfs(node.right, sum - node.val, path, result);
        }
        path.RemoveAt(path.Count - 1);
    }
}

In this Python solution, we perform a DFS and track the path and its cumulative sum. Upon meeting both the leaf and sum conditions, we add the path to the result using list operations for copying and backtracking.

Complexity

Time Complexity: O(N), where N represents the number of nodes.

Space Complexity: O(H), mainly for the recursion stack.

Try this approach in the editor

Approach 2: Iterative Depth-First Search with Stack

An iterative approach using a stack can also be used for this problem. We maintain stacks that parallel traditional DFS traversal with added structures to track path and cumulative sum states for efficient exploration of all feasible root-to-leaf paths.

#include <vector>
#include <stack>
using namespace std;

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};

class Solution {
public:
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        vector<vector<int>> result;
        if (!root) return result;
        stack<pair<TreeNode*, pair<int, vector<int>>>> stk;
        stk.push({root, {root->val, {root->val}}});
        while (!stk.empty()) {
            auto [node, state] = stk.top(); stk.pop();
            auto [currentSum, path] = state;
            if (!node->left && !node->right && currentSum == targetSum) {
                result.push_back(path);
            }
            if (node->right) {
                path.push_back(node->right->val);
                stk.push({node->right, {currentSum + node->right->val, path}});
                path.pop_back();
            }
            if (node->left) {
                path.push_back(node->left->val);
                stk.push({node->left, {currentSum + node->left->val, path}});
                path.pop_back();
            }
        }
        return result;
    }
};
function TreeNode(val, left, right) {
    this.val = (val===undefined ? 0 : val);
    this.left = (left===undefined ? null : left);
    this.right = (right===undefined ? null : right);
}

var pathSum = function(root, targetSum) {
    if (!root) return [];
    const result = [];
    const stack = [[root, root.val, [root.val]]];
    while (stack.length > 0) {
        const [node, sum, path] = stack.pop();
        if (node.left === null && node.right === null && sum === targetSum) {
            result.push(path);
        }
        if (node.right) {
            stack.push([node.right, sum + node.right.val, path.concat(node.right.val)]);
        }
        if (node.left) {
            stack.push([node.left, sum + node.left.val, path.concat(node.left.val)]);
        }
    }
    return result;
};

This C++ solution employs a stack to simulate DFS traversal iteratively. The stack holds node, cumulative sum, and path data. As each node is processed, we check for valid paths and update the result list accordingly. Paths are extended by exploring left and right children, augmented by the current node value.

Complexity

Time Complexity: O(N), as each node is processed exactly once.

Space Complexity: O(N), since results and stack can store all nodes during worst-case full-tree traversal.

Try this approach in the editor

Approach 3: DFS

We start from the root node, recursively traverse all paths from the root node to the leaf nodes, and record the path sum. When we traverse to a leaf node, if the current path sum equals targetSum, then we add this path to the answer.

The time complexity is O(n^2), where n is the number of nodes in the binary tree. The space complexity is O(n).

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func pathSum(root *TreeNode, targetSum int) (ans [][]int) {
	t := []int{}
	var dfs func(*TreeNode, int)
	dfs = func(root *TreeNode, s int) {
		if root == nil {
			return
		}
		s -= root.Val
		t = append(t, root.Val)
		if root.Left == nil && root.Right == nil && s == 0 {
			ans = append(ans, slices.Clone(t))
		}
		dfs(root.Left, s)
		dfs(root.Right, s)
		t = t[:len(t)-1]
	}
	dfs(root, targetSum)
	return
}
// Definition for a binary tree node.
// #[derive(Debug, PartialEq, Eq)]
// pub struct TreeNode {
//   pub val: i32,
//   pub left: Option<Rc<RefCell<TreeNode>>>,
//   pub right: Option<Rc<RefCell<TreeNode>>>,
// }
//
// impl TreeNode {
//   #[inline]
//   pub fn new(val: i32) -> Self {
//     TreeNode {
//       val,
//       left: None,
//       right: None
//     }
//   }
// }
use std::cell::RefCell;
use std::rc::Rc;
impl Solution {
    fn dfs(
        root: Option<Rc<RefCell<TreeNode>>>,
        paths: &mut Vec<i32>,
        mut target_sum: i32,
        res: &mut Vec<Vec<i32>>,
    ) {
        if let Some(node) = root {
            let mut node = node.borrow_mut();
            target_sum -= node.val;
            paths.push(node.val);
            if node.left.is_none() && node.right.is_none() {
                if target_sum == 0 {
                    res.push(paths.clone());
                }
            } else {
                if node.left.is_some() {
                    Self::dfs(node.left.take(), paths, target_sum, res);
                }
                if node.right.is_some() {
                    Self::dfs(node.right.take(), paths, target_sum, res);
                }
            }
            paths.pop();
        }
    }

    pub fn path_sum(root: Option<Rc<RefCell<TreeNode>>>, target_sum: i32) -> Vec<Vec<i32>> {
        let mut res = vec![];
        let mut paths = vec![];
        Self::dfs(root, &mut paths, target_sum, &mut res);
        res
    }
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Recursive Depth-First Search

Time Complexity: O(N), where N represents the number of nodes.

Space Complexity: O(H), mainly for the recursion stack.

Iterative Depth-First Search with Stack

Time Complexity: O(N), as each node is processed exactly once.

Space Complexity: O(N), since results and stack can store all nodes during worst-case full-tree traversal.

DFS–

Complexity analysis

ApproachTimeSpaceWhen to Use
Recursive DFS with BacktrackingO(n)O(h)Best general solution for exploring all root-to-leaf paths in a binary tree.
Iterative DFS with StackO(n)O(h)Useful when avoiding recursion or when stack-based traversal is preferred.

Frequently asked questions

Is Path Sum II easy or hard?

Path Sum II is considered a medium difficulty problem. The traversal itself is straightforward DFS, but the challenge comes from managing the path list correctly and applying backtracking so sibling branches do not reuse incorrect state.

How to solve Path Sum II in O(n)?

Perform a depth-first traversal starting from the root while maintaining the remaining target sum and the current path. Subtract the node value from the remaining sum as you go deeper. When you reach a leaf node and the remaining sum equals zero, record the path. Because each node is processed once, the traversal runs in O(n) time.

What is the best approach for Path Sum II?

Recursive depth-first search with backtracking is the most common solution. Traverse the tree while tracking the current path and remaining sum. When a leaf node is reached and the sum matches the target, store the path. This approach visits each node once and runs in O(n) time with O(h) recursion stack space.

What data structure is used in Path Sum II?

The core data structure is a binary tree. The solution typically uses recursion (call stack) or an explicit stack for DFS traversal, along with a dynamic list or array to track the current root-to-leaf path.

What is the time complexity of Path Sum II?

The traversal visits every node in the binary tree once, resulting in O(n) time complexity where n is the number of nodes. Additional work occurs when copying valid paths into the result list. The auxiliary space is O(h) for the recursion stack, where h is the height of the tree.

Path Sum II Python or Java solution approach?

Both Python and Java implementations usually follow the same recursive DFS pattern. Maintain a list representing the current path, subtract node values from the target during traversal, and backtrack after exploring each child. When a valid leaf path is found, copy the path into the result list.

Is Path Sum II asked at Google, Amazon, or Meta?

Path Sum II appears frequently in interviews that test tree traversal and recursion skills. Variants of the problem have been reported in interviews at Amazon, Google, Meta, and Microsoft because it evaluates DFS traversal, path tracking, and backtracking logic in binary trees.

Comments

Now write it yourselfClose this page and solve Path Sum II in the editor, without looking.
Practise Path Sum II