Efficient algorithm to find all the paths from A to Z?
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
Introduction
If you need all paths from node A to node Z, the standard approach is depth-first search with backtracking. The critical constraint is that "find all paths" can be exponentially expensive in the size of the graph, so the real goal is not to make it magically cheap, but to enumerate paths correctly without doing unnecessary work.
The Core Idea: DFS with Backtracking
For a graph stored as an adjacency list, DFS is the natural fit. You walk forward from the current node, add it to the current path, and backtrack after exploring each branch.
Here is a runnable Python example for all simple paths in a directed graph:
This prints every simple path from A to Z without revisiting nodes already in the current path.
Why "Efficient" Has a Hard Limit
There is an important theoretical limit here: if the graph contains many possible paths, the output itself can be enormous. No algorithm can list all paths faster than it takes to emit them.
That means the best practical algorithm is one that:
- avoids duplicate exploration
- avoids cycles in the current path
- uses memory proportional to the current path, not all possible branches at once
DFS with backtracking satisfies those requirements for most cases.
Handling Cycles Correctly
If the graph can contain cycles, you must prevent infinite recursion. The usual rule for "all simple paths" is to maintain a visited set for the current recursion branch only.
That detail matters. A global visited set would be wrong because it would block valid paths that reuse the same node through different branches.
Consider this graph:
Here, B and C connect to each other. Branch-local tracking prevents the search from bouncing forever while still allowing valid paths such as A -> B -> Z and A -> C -> Z.
If the Graph Is a DAG
When the graph is a directed acyclic graph, the problem becomes simpler because cycles are impossible. DFS still works well, and you can sometimes add memoization for counts or suffixes. But be careful: memoization is much more useful for counting paths than for materializing every path, because storing all suffix-path combinations can still become very large.
If you only need the number of paths, use dynamic programming instead of enumerating them:
That distinction is important. Counting paths and listing paths are different tasks with different cost profiles.
Practical Optimizations
You can still make DFS more practical:
- stop early if you only need the first
kpaths - prune branches using domain rules
- store the graph as an adjacency list
- avoid copying the whole path on every recursive step
In the first example, the code only copies the path when a complete path reaches the goal. During recursion it mutates one list and backtracks, which is much cheaper than allocating a new list at every edge.
Common Pitfalls
The biggest mistake is asking for all paths when what you really need is the shortest path or the path count. If you only need a shortest path, use BFS for unweighted graphs or Dijkstra's algorithm for weighted graphs.
Another mistake is using a global visited set for all DFS branches. That incorrectly suppresses valid paths.
Developers also underestimate the worst-case explosion in path count. Even a modest graph can have an impractically large number of paths, so "efficient" still needs to be evaluated against the required output size.
Finally, avoid representing the graph in a way that makes neighbor lookup expensive. An adjacency list is usually the right default for sparse graphs.
Summary
- To find all simple paths from
AtoZ, use DFS with backtracking. - The total number of paths can be exponential, so no algorithm can make full enumeration cheap in the worst case.
- Use branch-local cycle detection instead of one global
visitedset. - For DAGs, dynamic programming is excellent for counting paths but does not remove the cost of listing every path.
- Be clear whether you need all paths, the shortest path, or only the path count before choosing the algorithm.
Related reading
- efficient algorithm to find nearest point in a graph that does not have a known equation
- Efficient algorithm to find the largest rectangle from a set of points
- Efficient algorithm to get the combinations of all items in object
- Efficient Algorithm to obtain Points in a Circle around a Center
- Efficient Array Storage for Binary Tree
- Efficient Cartesian Product algorithm
- Efficient algorithm to randomly select items with frequency
- Efficient Algorithms for Computing a matrix times its transpose

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.