所有可能的路径
问题描述
给你一个有 n 个节点的 有向无环图(DAG),请你找出所有从节点 0 到节点 n-1 的路径并输出(不要求按特定顺序)
graph[i] 是一个从节点 i 可以访问的所有节点的列表(即从节点 i 到节点 graph[i][j]存在一条有向边)。
示例
示例 1:
输入:graph = [[1,2],[3],[3],[]]
输出:[[0,1,3],[0,2,3]]
解释:有两条路径 0 -> 1 -> 3 和 0 -> 2 -> 3
示例 2:
输入:graph = [[4,3,1],[3,2,4],[3],[4],[]]
输出:[[0,4],[0,3,4],[0,1,3,4],[0,1,2,3,4],[0,1,4]]
解题思路
采用深度优先进行路径搜索并用回溯法实现。
代码实现
java
class Solution {
//存放搜索过程中走过的节点
List<Integer> path = new ArrayList<>();
//存放所有可能路径
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> allPathsSourceTarget(int[][] graph) {
//处理0节点,将0节点放入走过的路径中
path.add(0);
//深度搜索0节点
dfs(0, graph);
return res;
}
//注意:此处graph也要传入用于判断节点之间是否有路径
void dfs (int node, int[][] graph) {
if (node == graph.length - 1) {
//若已走到终点将可能路径传入结果集
//注意:此处一定要用path新建一个对象后再存入res!
res.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < graph[node].length; i++) {
//处理graph[node][i]节点,将graph[node][i]节点放入走过的路径中
path.add(graph[node][i]);
//深度搜索该节点
dfs(graph[node][i], graph);
//回溯,将该节点移出可能路径,而后尝试对下一个节点的处理。
path.remove(path.size() - 1);
}
return;
}
}
注意事项
为什么一定要用path新建一个对象后再存入res?
因为如果直接将path存入res,则存入res的是path的引用。当所有的可能路径都搜索且回溯完毕后path = [0], 最后拿到的res将形如[[0],[0], [0]]。
复杂度
空间复杂度:O(n)
时间复杂度:O(n * 2^n)
th = [0], 最后拿到的res将形如[[0],[0], [0]]。
复杂度
空间复杂度:O(n)
时间复杂度:O(n * 2^n)
我们可以找到一种最坏情况,即每一个点都可以去往编号比它大的点。此时路径数为 O(2^n),且每条路径长度约为 O(n),因此总时间复杂度为 O(n * 2^n)。