Missing undo step on backtrack
Wrong move: Mutable state leaks between branches.
Usually fails on: Later branches inherit selections from earlier branches.
Fix: Always revert state changes immediately after recursive call.
Move from brute-force thinking to an efficient approach using backtracking strategy.
Given a directed acyclic graph (DAG) of n nodes labeled from 0 to n - 1, find all possible paths from node 0 to node n - 1 and return them in any order.
The graph is given as follows: graph[i] is a list of all nodes you can visit from node i (i.e., there is a directed edge from node i to node graph[i][j]).
Example 1:
Input: graph = [[1,2],[3],[3],[]] Output: [[0,1,3],[0,2,3]] Explanation: There are two paths: 0 -> 1 -> 3 and 0 -> 2 -> 3.
Example 2:
Input: graph = [[4,3,1],[3,2,4],[3],[4],[]] Output: [[0,4],[0,3,4],[0,1,3,4],[0,1,2,3,4],[0,1,4]]
Constraints:
n == graph.length2 <= n <= 150 <= graph[i][j] < ngraph[i][j] != i (i.e., there will be no self-loops).graph[i] are unique.Problem summary: Given a directed acyclic graph (DAG) of n nodes labeled from 0 to n - 1, find all possible paths from node 0 to node n - 1 and return them in any order. The graph is given as follows: graph[i] is a list of all nodes you can visit from node i (i.e., there is a directed edge from node i to node graph[i][j]).
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Backtracking
[[1,2],[3],[3],[]]
[[4,3,1],[3,2,4],[3],[4],[]]
number-of-ways-to-arrive-at-destination)number-of-increasing-paths-in-a-grid)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #797: All Paths From Source to Target
class Solution {
public List<List<Integer>> allPathsSourceTarget(int[][] graph) {
int n = graph.length;
Queue<List<Integer>> queue = new ArrayDeque<>();
queue.offer(Arrays.asList(0));
List<List<Integer>> ans = new ArrayList<>();
while (!queue.isEmpty()) {
List<Integer> path = queue.poll();
int u = path.get(path.size() - 1);
if (u == n - 1) {
ans.add(path);
continue;
}
for (int v : graph[u]) {
List<Integer> next = new ArrayList<>(path);
next.add(v);
queue.offer(next);
}
}
return ans;
}
}
// Accepted solution for LeetCode #797: All Paths From Source to Target
func allPathsSourceTarget(graph [][]int) [][]int {
var path []int
path = append(path, 0)
var ans [][]int
var dfs func(i int)
dfs = func(i int) {
if i == len(graph)-1 {
ans = append(ans, append([]int(nil), path...))
return
}
for _, j := range graph[i] {
path = append(path, j)
dfs(j)
path = path[:len(path)-1]
}
}
dfs(0)
return ans
}
# Accepted solution for LeetCode #797: All Paths From Source to Target
class Solution:
def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]:
n = len(graph)
q = deque([[0]])
ans = []
while q:
path = q.popleft()
u = path[-1]
if u == n - 1:
ans.append(path)
continue
for v in graph[u]:
q.append(path + [v])
return ans
// Accepted solution for LeetCode #797: All Paths From Source to Target
impl Solution {
fn dfs(i: usize, path: &mut Vec<i32>, res: &mut Vec<Vec<i32>>, graph: &Vec<Vec<i32>>) {
path.push(i as i32);
if i == graph.len() - 1 {
res.push(path.clone());
}
for j in graph[i].iter() {
Self::dfs(*j as usize, path, res, graph);
}
path.pop();
}
pub fn all_paths_source_target(graph: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
let mut res = Vec::new();
Self::dfs(0, &mut vec![], &mut res, &graph);
res
}
}
// Accepted solution for LeetCode #797: All Paths From Source to Target
function allPathsSourceTarget(graph: number[][]): number[][] {
const ans: number[][] = [];
const dfs = (path: number[]) => {
const curr = path.at(-1)!;
if (curr === graph.length - 1) {
ans.push([...path]);
return;
}
for (const v of graph[curr]) {
path.push(v);
dfs(path);
path.pop();
}
};
dfs([0]);
return ans;
}
Use this to step through a reusable interview workflow for this problem.
Generate every possible combination without any filtering. At each of n positions we choose from up to n options, giving nⁿ total candidates. Each candidate takes O(n) to validate. No pruning means we waste time on clearly invalid partial solutions.
Backtracking explores a decision tree, but prunes branches that violate constraints early. Worst case is still factorial or exponential, but pruning dramatically reduces the constant factor in practice. Space is the recursion depth (usually O(n) for n-level decisions).
Review these before coding to avoid predictable interview regressions.
Wrong move: Mutable state leaks between branches.
Usually fails on: Later branches inherit selections from earlier branches.
Fix: Always revert state changes immediately after recursive call.