# 797. All Paths From Source to Target - LeetCode Python/Java/C++/JS code
Visit original link: [797. All Paths From Source to Target - LeetCode Python/Java/C++/JS code](https://leetcodepython.com/en/leetcode/797-all-paths-from-source-to-target) for a better experience!
LeetCode link: [797. All Paths From Source to Target](https://leetcode.com/problems/all-paths-from-source-to-target), difficulty: **Medium**.
## LeetCode description of "797. All Paths From Source to Target"
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.length`
- `2 <= n <= 15`
- `0 <= graph[i][j] < n`
- `graph[i][j] != i` (i.e., there will be no self-loops).
- All the elements of `graph[i]` are **unique**.
- The input graph is **guaranteed** to be a **DAG**.
## Intuition 1
## Pattern of "Depth-First Search"
**Depth-First Search (DFS)** is a classic graph traversal algorithm characterized by its **"go as deep as possible"** approach when exploring branches of a graph. Starting from the initial vertex, DFS follows a single path as far as possible until it reaches a vertex with no unvisited adjacent nodes, then backtracks to the nearest branching point to continue exploration. This process is implemented using **recursion** or an **explicit stack (iterative method)**, resulting in a **Last-In-First-Out (LIFO)** search order. As a result, DFS can quickly reach deep-level nodes far from the starting point in unweighted graphs.
**Comparison with BFS**:
1. **Search Order**: DFS prioritizes depth-wise exploration, while Breadth-First Search (BFS) expands layer by layer, following a **First-In-First-Out (FIFO)** queue structure.
2. **Use Cases**: DFS is better suited for strongly connected components or backtracking problems (e.g., finding all paths in a maze), whereas BFS excels at finding the shortest path (in unweighted graphs) or exploring neighboring nodes (e.g., friend recommendations in social networks).
**Unique Aspects of DFS**:
- **Incompleteness**: If the graph is infinitely deep or contains cycles (without visited markers), DFS may fail to terminate, whereas BFS always finds the shortest path (in unweighted graphs).
- **"One-path deep-dive"** search style makes it more flexible for backtracking, pruning, or path recording, but it may also miss near-optimal solutions.
In summary, DFS reveals the vertical structure of a graph through its depth-first strategy. Its inherent backtracking mechanism, combined with the natural use of a stack, makes it highly effective for path recording and state-space exploration. However, precautions must be taken to handle cycles and the potential absence of optimal solutions.
## Step by Step Solutions
1. Initialize an empty list `paths` to store all valid paths found.
2. Initialize a stack to manage the DFS traversal. Each element on the stack will store a pair (or tuple) containing the current `node` and the `path` taken to reach that node.
3. Push the starting state onto the stack: the initial node `0` and an empty path list (e.g., `(0, [])`).
4. While the stack is not empty:
- Pop the top element from the stack, retrieving the current `node` and its associated `path`.
- Create a `currentPath` list by appending the current `node` to the `path` popped from the stack. This represents the path leading up to and including the current node.
- Check if the current `node` is the target node (`n - 1`, where `n` is the total number of nodes).
- If it is the target node, add the `currentPath` to the `paths` list, as a complete path from source to target has been found.
- If it is not the target node, iterate through all `neighbor` nodes accessible from the current `node` (i.e., iterate through `graph[node]`).
- For each `neighbor`, push a new pair onto the stack: the `neighbor` node and the `currentPath`. This prepares the traversal to explore paths extending from the neighbor.
5. After the loop finishes (stack is empty), return the `paths` list containing all discovered paths from node `0` to node `n - 1`.
## Complexity
- Time complexity: `Too complex`.
- Space complexity: `Too complex`.
## Python
```python
class Solution:
def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]:
paths = []
stack = [(0, [])]
while stack:
node, path = stack.pop()
if node == len(graph) - 1:
paths.append(path + [node])
continue
for target_node in graph[node]:
stack.append((target_node, path + [node]))
return paths
```
## Java
```java
class Solution {
public List> allPathsSourceTarget(int[][] graph) {
List> paths = new ArrayList<>();
// Each element in the stack is a pair: (current_node, current_path)
Stack>> stack = new Stack<>();
List initialPath = new ArrayList<>();
stack.push(new Pair<>(0, initialPath));
int targetNode = graph.length - 1;
while (!stack.isEmpty()) {
var current = stack.pop();
int node = current.getKey();
var path = current.getValue();
var nextPath = new ArrayList<>(path);
nextPath.add(node);
if (node == targetNode) {
paths.add(nextPath);
continue;
}
for (int neighbor : graph[node]) {
stack.push(new Pair<>(neighbor, nextPath));
}
}
return paths;
}
}
```
## C++
```cpp
class Solution {
public:
vector> allPathsSourceTarget(vector>& graph) {
vector> paths;
// Stack stores pairs of (current_node, current_path)
stack>> s;
s.push({0, {}}); // Start at node 0 with an empty path initially
int targetNode = graph.size() - 1;
while (!s.empty()) {
auto node_path = s.top();
s.pop();
int node = node_path.first;
vector path = node_path.second;
// Add the current node to the path
path.push_back(node);
if (node == targetNode) {
paths.push_back(path); // Found a path to the target
continue;
}
// Explore neighbors
for (int neighbor : graph[node]) {
s.push({neighbor, path});
}
}
return paths;
}
};
```
## JavaScript
```javascript
/**
* @param {number[][]} graph
* @return {number[][]}
*/
var allPathsSourceTarget = function(graph) {
const paths = [];
// Stack stores arrays: [current_node, current_path]
const stack = [[0, []]]; // Start at node 0 with an empty path
const targetNode = graph.length - 1;
while (stack.length > 0) {
const [node, path] = stack.pop();
// Create the new path by appending the current node
const currentPath = [...path, node];
if (node === targetNode) {
paths.push(currentPath); // Found a path
continue;
}
// Explore neighbors
for (const neighbor of graph[node]) {
stack.push([neighbor, currentPath]); // Push neighbor and the path so far
}
}
return paths;
};
```
## C#
```csharp
public class Solution {
public IList> AllPathsSourceTarget(int[][] graph)
{
var paths = new List>();
// Stack stores tuples: (current_node, current_path)
var stack = new Stack<(int node, List path)>();
stack.Push((0, new List())); // Start at node 0
int targetNode = graph.Length - 1;
while (stack.Count > 0)
{
var (node, path) = stack.Pop();
var currentPath = new List(path);
currentPath.Add(node);
if (node == targetNode)
{
paths.Add(currentPath); // Found a path
continue;
}
// Explore neighbors
foreach (int neighbor in graph[node])
{
stack.Push((neighbor, currentPath)); // Push neighbor and the path so far
}
}
return paths;
}
}
```
## Go
```go
type StackItem struct {
Node int
Path []int
}
func allPathsSourceTarget(graph [][]int) [][]int {
var paths [][]int
stack := []StackItem{{Node: 0, Path: []int{}}} // Start at node 0
targetNode := len(graph) - 1
for len(stack) > 0 {
currentItem := stack[len(stack) - 1] // Pop from stack
stack = stack[:len(stack) - 1]
node := currentItem.Node
path := currentItem.Path
newPath := append([]int(nil), path...)
newPath = append(newPath, node)
if node == targetNode {
paths = append(paths, newPath) // Found a path
continue
}
for _, neighbor := range graph[node] {
stack = append(stack, StackItem{Node: neighbor, Path: newPath})
}
}
return paths
}
```
## Ruby
```ruby
# @param {Integer[][]} graph
# @return {Integer[][]}
def all_paths_source_target(graph)
paths = []
# Stack stores arrays: [current_node, current_path]
stack = [[0, []]] # Start at node 0 with an empty path
target_node = graph.length - 1
while !stack.empty?
node, path = stack.pop
# Create the new path by appending the current node
current_path = path + [node]
if node == target_node
paths << current_path # Found a path
next
end
# Explore neighbors
graph[node].each do |neighbor|
stack.push([neighbor, current_path])
end
end
paths
end
```
## Other languages
```java
// Welcome to create a PR to complete the code of this language, thanks!
```
## Intuition 2
## Pattern of "Depth-First Search"
**Depth-First Search (DFS)** is a classic graph traversal algorithm characterized by its **"go as deep as possible"** approach when exploring branches of a graph. Starting from the initial vertex, DFS follows a single path as far as possible until it reaches a vertex with no unvisited adjacent nodes, then backtracks to the nearest branching point to continue exploration. This process is implemented using **recursion** or an **explicit stack (iterative method)**, resulting in a **Last-In-First-Out (LIFO)** search order. As a result, DFS can quickly reach deep-level nodes far from the starting point in unweighted graphs.
**Comparison with BFS**:
1. **Search Order**: DFS prioritizes depth-wise exploration, while Breadth-First Search (BFS) expands layer by layer, following a **First-In-First-Out (FIFO)** queue structure.
2. **Use Cases**: DFS is better suited for strongly connected components or backtracking problems (e.g., finding all paths in a maze), whereas BFS excels at finding the shortest path (in unweighted graphs) or exploring neighboring nodes (e.g., friend recommendations in social networks).
**Unique Aspects of DFS**:
- **Incompleteness**: If the graph is infinitely deep or contains cycles (without visited markers), DFS may fail to terminate, whereas BFS always finds the shortest path (in unweighted graphs).
- **"One-path deep-dive"** search style makes it more flexible for backtracking, pruning, or path recording, but it may also miss near-optimal solutions.
In summary, DFS reveals the vertical structure of a graph through its depth-first strategy. Its inherent backtracking mechanism, combined with the natural use of a stack, makes it highly effective for path recording and state-space exploration. However, precautions must be taken to handle cycles and the potential absence of optimal solutions.
## Pattern of "Recursion"
Recursion is an important concept in computer science and mathematics, which refers to the method by which a function calls itself **directly or indirectly** in its definition.
### The core idea of recursion
- **Self-call**: A function calls itself during execution.
- **Base case**: Equivalent to the termination condition. After reaching the base case, the result can be returned without recursive calls to prevent infinite loops.
- **Recursive step**: The step by which the problem gradually approaches the "base case".
## Step by Step Solutions
1. Initialize an empty list `paths` to store all the valid paths found from source to target.
2. Define a recursive Depth-First Search (DFS) function, say `dfs`, that takes the current `node` and the `currentPath` (a list of nodes visited so far to reach the current node) as input.
3. Inside the `dfs` function:
a. Create a new path list by appending the current `node` to the `currentPath`. Let's call this `newPath`.
b. Check if the current `node` is the target node (`n - 1`, where `n` is the total number of nodes).
i. If it is the target node, it means we've found a complete path. Add `newPath` to the main `paths` list and return from this recursive call.
c. If the current `node` is not the target node, iterate through all `neighbor` nodes accessible from the current `node` (i.e., iterate through `graph[node]`).
i. For each `neighbor`, make a recursive call to `dfs` with the `neighbor` as the new current node and `newPath` as the path taken to reach it (`dfs(neighbor, newPath)`).
4. Start the process by calling the `dfs` function with the source node `0` and an empty initial path (`dfs(0, [])`).
5. After the initial `dfs` call completes, return the `paths` list containing all discovered paths.
## Complexity
- Time complexity: `Too complex`.
- Space complexity: `Too complex`.
## Python
```python
class Solution:
def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]:
self.paths = []
self.graph = graph
self.target = len(graph) - 1
self.dfs(0, []) # Start DFS from node 0 with an empty initial path
return self.paths
def dfs(self, node, path):
current_path = path + [node]
if node == self.target: # Base case
self.paths.append(current_path)
return
for neighbor in self.graph[node]: # Recursive step: Explore neighbors
self.dfs(neighbor, current_path)
```
## Java
```java
class Solution {
private List> paths;
private int[][] graph;
private int targetNode;
public List> allPathsSourceTarget(int[][] graph) {
this.paths = new ArrayList<>();
this.graph = graph;
this.targetNode = graph.length - 1;
List initialPath = new ArrayList<>();
dfs(0, initialPath); // Start DFS from node 0 with an empty initial path
return paths;
}
private void dfs(int node, List currentPath) {
List newPath = new ArrayList<>(currentPath);
newPath.add(node);
if (node == targetNode) { // Base case
paths.add(newPath);
return;
}
for (int neighbor : graph[node]) { // Recursive step: Explore neighbors
dfs(neighbor, newPath);
}
}
}
```
## C++
```cpp
class Solution {
public:
vector> allPathsSourceTarget(vector>& graph) {
_graph = graph;
vector initial_path; // Empty initial path
dfs(0, initial_path); // Start DFS from node 0
return _paths;
}
private:
vector> _paths;
vector> _graph;
void dfs(int node, vector current_path) {
current_path.push_back(node);
if (node == _graph.size() - 1) { // Base case
_paths.push_back(current_path);
return;
}
for (int neighbor : _graph[node]) { // Recursive step: Explore neighbors
dfs(neighbor, current_path);
}
}
};
```
## JavaScript
```javascript
let paths
let graph
var allPathsSourceTarget = function (graph_) {
paths = []
graph = graph_
dfs(0, [])
return paths
}
function dfs(node, currentPath) {
const newPath = [...currentPath, node]
if (node === graph.length - 1) { // Base case
paths.push(newPath)
return
}
for (const neighbor of graph[node]) { // Recursive step: Explore neighbors
dfs(neighbor, newPath)
}
}
```
## C#
```csharp
public class Solution
{
private IList> paths;
private int[][] graph;
private int targetNode;
public IList> AllPathsSourceTarget(int[][] graph)
{
this.paths = new List>();
this.graph = graph;
this.targetNode = graph.Length - 1;
Dfs(0, new List());
return paths;
}
private void Dfs(int node, List currentPath)
{
var newPath = new List(currentPath);
newPath.Add(node);
if (node == targetNode) // Base case
{
paths.Add(newPath);
return;
}
foreach (int neighbor in graph[node]) // Recursive step: Explore neighbors
{
Dfs(neighbor, newPath);
}
}
}
```
## Go
```go
var (
paths [][]int
graph [][]int
targetNode int
)
func allPathsSourceTarget(graph_ [][]int) [][]int {
paths = [][]int{}
graph = graph_
targetNode = len(graph) - 1
dfs(0, []int{})
return paths
}
func dfs(node int, currentPath []int) {
newPath := append([]int(nil), currentPath...)
newPath = append(newPath, node)
if node == targetNode { // Base case
paths = append(paths, newPath)
return
}
for _, neighbor := range graph[node] { // Recursive step: Explore neighbors
dfs(neighbor, newPath)
}
}
```
## Ruby
```ruby
def all_paths_source_target(graph)
@paths = []
@graph = graph
dfs(0, [])
@paths
end
def dfs(node, current_path)
new_path = current_path + [node]
if node == @graph.size - 1 # Base case
@paths << new_path
return
end
@graph[node].each do |neighbor| # Recursive step: Explore neighbors
dfs(neighbor, new_path)
end
end
```
## Other languages
```java
// Welcome to create a PR to complete the code of this language, thanks!
```
## Intuition 3
## Pattern of "Depth-First Search"
**Depth-First Search (DFS)** is a classic graph traversal algorithm characterized by its **"go as deep as possible"** approach when exploring branches of a graph. Starting from the initial vertex, DFS follows a single path as far as possible until it reaches a vertex with no unvisited adjacent nodes, then backtracks to the nearest branching point to continue exploration. This process is implemented using **recursion** or an **explicit stack (iterative method)**, resulting in a **Last-In-First-Out (LIFO)** search order. As a result, DFS can quickly reach deep-level nodes far from the starting point in unweighted graphs.
**Comparison with BFS**:
1. **Search Order**: DFS prioritizes depth-wise exploration, while Breadth-First Search (BFS) expands layer by layer, following a **First-In-First-Out (FIFO)** queue structure.
2. **Use Cases**: DFS is better suited for strongly connected components or backtracking problems (e.g., finding all paths in a maze), whereas BFS excels at finding the shortest path (in unweighted graphs) or exploring neighboring nodes (e.g., friend recommendations in social networks).
**Unique Aspects of DFS**:
- **Incompleteness**: If the graph is infinitely deep or contains cycles (without visited markers), DFS may fail to terminate, whereas BFS always finds the shortest path (in unweighted graphs).
- **"One-path deep-dive"** search style makes it more flexible for backtracking, pruning, or path recording, but it may also miss near-optimal solutions.
In summary, DFS reveals the vertical structure of a graph through its depth-first strategy. Its inherent backtracking mechanism, combined with the natural use of a stack, makes it highly effective for path recording and state-space exploration. However, precautions must be taken to handle cycles and the potential absence of optimal solutions.
## Step by Step Solutions
1. Initialize an empty list `paths` to store all valid paths found from the source to the target.
2. Create a mutable list `path` to track the current path being explored, initially containing only the source node `0`.
3. Implement a recursive DFS function that explores paths using backtracking:
- Base case: If the current node is the target node (`n-1`), make a copy of the current path and add it to the `paths` list.
- Recursive step: For each neighbor of the current node:
- Add the neighbor to the current path.
- Recursively call the DFS function with this neighbor.
- After the recursive call returns, remove the neighbor from the path (backtrack).
4. Start the DFS from the source node `0`.
5. Return the collected `paths` after the DFS completes.
## Complexity
- Time complexity: `Too complex`.
- Space complexity: `Too complex`.
## Python
```python
class Solution:
def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]:
self.paths = []
self.graph = graph
self.path = [0] # Important
self.dfs(0)
return self.paths
def dfs(self, node):
if node == len(self.graph) - 1:
self.paths.append(self.path.copy()) # Important
return
for neighbor in self.graph[node]:
self.path.append(neighbor) # Important
self.dfs(neighbor)
self.path.pop() # Important
```
## Java
```java
class Solution {
private List> paths = new ArrayList<>();
private List path = new ArrayList<>(List.of(0)); // Important - start with node 0
private int[][] graph;
public List> allPathsSourceTarget(int[][] graph) {
this.graph = graph;
dfs(0);
return paths;
}
private void dfs(int node) {
if (node == graph.length - 1) { // Base case
paths.add(new ArrayList<>(path)); // Important - make a copy
return;
}
for (int neighbor : graph[node]) { // Recursive step
path.add(neighbor); // Important
dfs(neighbor);
path.remove(path.size() - 1); // Important - backtrack
}
}
}
```
## C++
```cpp
class Solution {
public:
vector> allPathsSourceTarget(vector>& graph) {
_graph = graph;
_path = {0}; // Important - start with node 0
dfs(0);
return _paths;
}
private:
vector> _paths;
vector> _graph;
vector _path;
void dfs(int node) {
if (node == _graph.size() - 1) { // Base case
_paths.push_back(_path); // Important - copy is made automatically
return;
}
for (int neighbor : _graph[node]) { // Recursive step
_path.push_back(neighbor); // Important
dfs(neighbor);
_path.pop_back(); // Important - backtrack
}
}
};
```
## JavaScript
```javascript
/**
* @param {number[][]} graph
* @return {number[][]}
*/
var allPathsSourceTarget = function(graph) {
const paths = [];
const path = [0]; // Important - start with node 0
function dfs(node) {
if (node === graph.length - 1) { // Base case
paths.push([...path]); // Important - make a copy
return;
}
for (const neighbor of graph[node]) { // Recursive step
path.push(neighbor); // Important
dfs(neighbor);
path.pop(); // Important - backtrack
}
}
dfs(0);
return paths;
};
```
## C#
```csharp
public class Solution
{
private IList> paths = new List>();
private List path = new List { 0 }; // Important - start with node 0
private int[][] graph;
public IList> AllPathsSourceTarget(int[][] graph)
{
this.graph = graph;
Dfs(0);
return paths;
}
private void Dfs(int node)
{
if (node == graph.Length - 1)
{ // Base case
paths.Add(new List(path)); // Important - make a copy
return;
}
foreach (int neighbor in graph[node])
{ // Recursive step
path.Add(neighbor); // Important
Dfs(neighbor);
path.RemoveAt(path.Count - 1); // Important - backtrack
}
}
}
```
## Go
```go
func allPathsSourceTarget(graph [][]int) [][]int {
paths := [][]int{}
path := []int{0} // Important - start with node 0
var dfs func(int)
dfs = func(node int) {
if node == len(graph) - 1 { // Base case
// Important - make a deep copy of the path
paths = append(paths, append([]int(nil), path...))
return
}
for _, neighbor := range graph[node] { // Recursive step
path = append(path, neighbor) // Important
dfs(neighbor)
path = path[:len(path) - 1] // Important - backtrack
}
}
dfs(0)
return paths
}
```
## Ruby
```ruby
# @param {Integer[][]} graph
# @return {Integer[][]}
def all_paths_source_target(graph)
@paths = []
@graph = graph
@path = [0] # Important - start with node 0
dfs(0)
@paths
end
def dfs(node)
if node == @graph.length - 1 # Base case
@paths << @path.clone # Important - make a copy
return
end
@graph[node].each do |neighbor| # Recursive step
@path << neighbor # Important
dfs(neighbor)
@path.pop # Important - backtrack
end
end
```
## Other languages
```java
// Welcome to create a PR to complete the code of this language, thanks!
```
Dear LeetCoders! For a better LeetCode problem-solving experience, please visit website [LeetCodePython.com](https://leetcodepython.com): Dare to claim the best practices of LeetCode solutions! Will save you a lot of time!
Original link: [797. All Paths From Source to Target - LeetCode Python/Java/C++/JS code](https://leetcodepython.com/en/leetcode/797-all-paths-from-source-to-target).
GitHub repository: [f*ck-leetcode](https://github.com/fuck-leetcode/fuck-leetcode).