Skip to content
Work Practice Products Coding interviews Machine learning coding Quant developer HFT course Blog Method Why me About Enquire Book a call

Coding · Graphs

The depth-first search pattern: exploring every path

Lesson · 10 min read · Graphs · Pattern: depth-first search

When the question is about paths themselves (all of them, or the ones with a property), search depth-first and undo each step on the way back.

What the pattern is

A plain traversal marks a node once and never visits it again; that is enough to know what is reachable. Some problems ask about the paths instead: list every route from A to B, count the routes whose weights add to a target, find a route that visits every node once. Two different paths may share a node, so a node cannot be marked for good. It is marked while it is on the current path and unmarked when the search backs out of it. This is backtracking on a graph.

Depth-first search over paths

explore(u, path)

  1. Add u to onPath and to path.
  2. If u is the target (and the path satisfies the condition), record or count the path.
  3. Otherwise, for each neighbour v not in onPath: explore(v, path).
  4. Remove u from path and onPath (backtrack).

How to recognise it

  • The output is a set of paths, or a count of paths, rather than one distance or one yes/no.
  • The words "all", "every possible", "simple path", "visit each exactly once", "route whose total equals".
  • Small inputs: n up to 10–20 nodes. The number of paths can grow exponentially, and the constraints say the problem setter knows it.

If the graph is a DAG (as in "all paths from 0 to n − 1" on LeetCode), no node can repeat on a path, so onPath is not even needed. Keep it anyway when you are not sure the input is acyclic.

Worked example: every path from 0 to 4

On the directed graph below, list every path from 0 to 4. Watch nodes leave the path when the search backs out of them.

Backtracking from 0; neighbours tried in increasing order.

  1. Step 1 / 18
    01234
    current path
    00
    paths found
    none yet0

    Start at 0, the only node on the path.

  2. Step 2 / 18
    01234
    current path
    0011
    paths found
    none yet0

    Extend the path to 1.

  3. Step 3 / 18
    01234
    current path
    001122
    paths found
    none yet0

    Extend the path to 2.

  4. Step 4 / 18
    01234
    current path
    00112233
    paths found
    none yet0

    Extend the path to 3.

  5. Step 5 / 18
    01234
    current path
    0011223344
    paths found
    012340

    Reached 4: record the path 0 → 1 → 2 → 3 → 4. Then back up to look for others.

  6. Step 6 / 18
    01234
    current path
    001122
    paths found
    012340

    Every way on from 3 is explored: remove 3 from the path so other paths may use it.

  7. Step 7 / 18
    01234
    current path
    00112243
    paths found
    01234001241

    Reached 4: record the path 0 → 1 → 2 → 4. Then back up to look for others.

  8. Step 8 / 18
    01234
    current path
    0011
    paths found
    01234001241

    Every way on from 2 is explored: remove 2 from the path so other paths may use it.

  9. Step 9 / 18
    01234
    current path
    001132
    paths found
    01234001241

    Extend the path to 3.

  10. Step 10 / 18
    01234
    current path
    00113243
    paths found
    0123400124101342

    Reached 4: record the path 0 → 1 → 3 → 4. Then back up to look for others.

  11. Step 11 / 18
    01234
    current path
    0011
    paths found
    0123400124101342

    Every way on from 3 is explored: remove 3 from the path so other paths may use it.

  12. Step 12 / 18
    01234
    current path
    00
    paths found
    0123400124101342

    Every way on from 1 is explored: remove 1 from the path so other paths may use it.

  13. Step 13 / 18
    01234
    current path
    0021
    paths found
    0123400124101342

    Extend the path to 2.

  14. Step 14 / 18
    01234
    current path
    002132
    paths found
    0123400124101342

    Extend the path to 3.

  15. Step 15 / 18
    01234
    current path
    00213243
    paths found
    012340012410134202343

    Reached 4: record the path 0 → 2 → 3 → 4. Then back up to look for others.

  16. Step 16 / 18
    01234
    current path
    0021
    paths found
    012340012410134202343

    Every way on from 3 is explored: remove 3 from the path so other paths may use it.

  17. Step 17 / 18
    01234
    current path
    002142
    paths found
    0123400124101342023430244

    Reached 4: record the path 0 → 2 → 4. Then back up to look for others.

  18. Step 18 / 18
    01234
    current path
    00
    paths found
    0123400124101342023430244

    Every way on from 2 is explored: remove 2 from the path so other paths may use it. Search finished: 5 paths.

current nodeon the current pathtarget

TimeO(number of paths × n)
SpaceO(n) for the current path

Exponential in the worst case: a graph can have more than (n − 2)! simple paths between two nodes. That is why these problems come with small n, and why pruning (stop as soon as a partial sum exceeds the target, for instance) matters.

The problems in this module: