Binary Tree Paths

EasyTrees · DFS · Backtracking🧩 Tree DFSLeetCode #257 ↗Updated

Problem

Given the root of a binary tree, list every path that starts at the root and ends at a leaf (a node with no children). Write each path as its node values joined by "->", e.g. "1->2->5". The paths may be returned in any order.
Input[1,2,3,null,5]Output["1->2->5","1->3"]
Input[1]Output["1"]

1 ≤ nodes ≤ 100  ·  -100 ≤ Node.val ≤ 100

Try it yourself

Java
class Solution {
    public List<String> binaryTreePaths(TreeNode root) {
        
    }
}
Your code is saved in this browser.Submit on LeetCode ↗
Key insight
A root-to-leaf path is exactly the DFS recursion stack at the moment you reach a leaf. Keep one shared buffer for that stack: append on the way down, snapshot it at a leaf, and truncate it on the way back up.
PatternTree DFS

Instinct If the answer for a node can be built from the answers of its left and right subtrees, write one recursive function and trust it on the children.

Memory hack Ask the kids, then decide - each child reports up, the parent combines, and a global variable keeps the best "bend" seen so far.

Open the Tree DFS guide →

Approaches

Brute ForceCombine Child Paths (Divide & Conquer)

Time O(n + L·h²)Space O(L·h)

A leaf's only path is its own value. Any other node asks each child for all of its paths and prefixes val + "->" to every one. Correct by induction, but each of the L leaf paths is rebuilt as a new string at every one of its up to h ancestors.

Java
public List<String> binaryTreePaths(TreeNode root) {
    List<String> res = new ArrayList<>();
    if (root == null) return res;
    if (root.left == null && root.right == null) {
        res.add(String.valueOf(root.val));
        return res;
    }
    for (TreeNode child : new TreeNode[] {root.left, root.right}) {
        for (String tail : binaryTreePaths(child)) {
            res.add(root.val + "->" + tail); // rebuild every path below
        }
    }
    return res;
}

Clean recursion, but repeated string rebuilding costs a factor of h.

At a glance

LevelApproachTimeSpace
Brute ForceCombine Child Paths (Divide & Conquer)O(n + L·h²)O(L·h)
BetterTop-Down DFS Passing a StringO(n·h)O(h²)
OptimalDFS with a Backtracking StringBuilderO(n + L·h)O(h)
Common pitfalls
  • Adding a path at a null child instead of at a real leaf — one-child nodes yield bogus paths.
  • Forgetting to restore the builder — later paths inherit stale values.
  • Appending "->" before the first value → paths like "->1->2".
Interview tips
  • Define a leaf precisely (both children null) before writing code.
  • Start with string passing, then mention the StringBuilder backtracking optimisation.
  • Note the output alone can be O(L·h), so that term is unavoidable.
Pattern
DFS + backtracking path buffer → enumerate or check every root-to-leaf path (sums, strings, numbers).
My notes saved in this browser