All Paths From Source to Target

LeetCode 797 · View on LeetCode

Find all paths from node 0 to node n-1 in a DAG. The graph is given as an adjacency list: graph[i] lists neighbors of node i. No visited set needed — it's a DAG (no cycles).

DFS Backtracking (memory efficient)

Reuses one path slice, only copies when a complete path is found.

package main

import "fmt"

func allPathsSourceTarget(graph [][]int) [][]int {
	result := [][]int{}
	path := []int{0}

	var dfs func(node int)
	dfs = func(node int) {
		if node == len(graph)-1 {
			result = append(result, append([]int{}, path...))
			return
		}
		for _, nei := range graph[node] {
			path = append(path, nei)
			dfs(nei)
			path = path[:len(path)-1] // backtrack
		}
	}

	dfs(0)
	return result
}

func main() {
	graph := [][]int{{1, 2}, {3}, {3}, {}}
	fmt.Println(allPathsSourceTarget(graph)) // [[0 1 3] [0 2 3]]
}

BFS with Path Tracking

Each queue entry stores an entire path. Simpler logic but copies the path at every step.

package main

import "fmt"

func allPathsSourceTarget(graph [][]int) [][]int {
	result := [][]int{}
	queue := [][]int{{0}}

	for len(queue) > 0 {
		path := queue[0]
		queue = queue[1:]
		node := path[len(path)-1]
		if node == len(graph)-1 {
			result = append(result, path)
			continue
		}
		for _, nei := range graph[node] {
			newPath := make([]int, len(path)+1)
			copy(newPath, path)
			newPath[len(path)] = nei
			queue = append(queue, newPath)
		}
	}
	return result
}

func main() {
	graph := [][]int{{1, 2}, {3}, {3}, {}}
	fmt.Println(allPathsSourceTarget(graph)) // [[0 1 3] [0 2 3]]
}

Comparison

DFS Backtracking BFS Path Tracking
Memory O(depth) for path + O(results) O(all paths × avg length) in queue
Style Recursive, reuses one slice Iterative, copies at every step
When Preferred — less allocation When you need shortest paths first
▶ Open Go Playground

Copy the code above and paste to run

© 2026 ByteLearn.dev. Free courses for developers. · Privacy