leetcode每日一题系列-所有可能的路径-「DFS」-「BFS」-「DFS+记忆化搜索」

1,181 阅读1分钟

这是我参与8月更文挑战的第25天,活动详情查看:8月更文挑战

leetcode-797-所有可能的路径

[博客链接]

菜🐔的学习之路

掘金首页

[题目描述]

给你一个有 n 个节点的 有向无环图 (DAG),请你找出所有从节点 0 到节点 n-1 的路径并输出(不要求按特定顺序)

二维数组的第 i 个数组中的单元都表示有向图中 i 号节点所能到达的下一些节点,空就是没有下一个结点了。

译者注:有向图是有方向的,即规定了 a→b 你就不能从 b→a 。

示例 1:

输入:graph = [[1,2],[3],[3],[]]
输出:[[0,1,3],[0,2,3]]
解释:有两条路径 0 -> 1 -> 30 -> 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]]

示例 3:

输入:graph = [[1],[]]
输出:[[0,1]]

示例 4:

输入:graph = [[1,2,3],[2],[3],[]]
输出:[[0,1,2,3],[0,2,3],[0,3]]

示例 5:

输入:graph = [[1,3],[2],[3],[]]
输出:[[0,1,2,3],[0,3]]

提示:

  • n == graph.length
  • 2 <= n <= 15
  • 0 <= graph[i][j] < n
  • graph[i][j] != i(即,不存在自环)
  • graph[i] 中的所有元素 互不相同
  • 保证输入为 有向无环图(DAG)

Related Topics

  • 深度优先搜索
  • 广度优先搜索
  • 回溯
  • 👍 154 👎 0

[题目链接]

leetcode题目链接

[github地址]

代码链接

[思路介绍]

思路一:DFS+暴力

  • 这道题没有什么特殊限制整体还是很好做dfs暴搜的
  • dfs遍历
List<List<Integer>> res = new ArrayList<>();
int[][] g;
int n;
public List<List<Integer>> allPathsSourceTarget(int[][] graph) {
    g = graph;
    n = graph.length;
    List<Integer> list = new ArrayList<>();
    dfs(list, 0);
    return res;
}
public void dfs(List<Integer> list, int num) {
    list.add(num);
    if (num == n - 1) {
        res.add(list);
        return;
    }
    for (int temp: g[num]
         ) {
        List<Integer> tempList = new ArrayList<>(list);
        dfs(tempList,temp);
    }
}
  • 时间复杂度O(n2n)O(n*2^{n})
  • 空间复杂度O(n2n)O(n*2^{n})

思路二:BFS

  • 毫无疑问也可以用bfs搜索进行遍历
  • 需要定义一个临时path记录之前遍历过的状态,获取完整路径
public List<List<Integer>> allPathsSourceTarget(int[][] graph) {
    int n = graph.length;
    Queue<List<Integer>> q = new LinkedList<>();
    q.add(new ArrayList<Integer>() {{
        add(0);
    }});
    List<List<Integer>> res = new ArrayList<>();
    while (!q.isEmpty()) {
        List<Integer> poll = q.poll();
        int temp = poll.get(poll.size() - 1);
        if (temp == n - 1) {
            res.add(poll);
        } else {
            for (int val: graph[temp]
                 ) {
                List<Integer> newList = new ArrayList<>(poll);
                newList.add(val);
                q.add(newList);
            }
        }
    }
    return res;
}
  • 时间复杂度O(n2n)O(n*2^{n})
  • 空间复杂度O(n2n)O(n*2^{n})

思路三:dfs+记忆化搜索

  • 其实这道题记忆化搜索的代码复杂程度让人恶心
  • 感觉这种能不用也可以不用
  • 定义map记录每个节点的所有状态
  • 返回最终n-1 记录的map节点
  • 通过**list.add(index,num)**来插入头节点
  • 记录的是后效性状态
  • 也就是说先搜索出来的是最后的节点,然后一层层一层往头节点开始插入
  • 最后返回res
int[][] g;
int n;
Map<Integer,List<List<Integer>>> cache = new HashMap<>();
public List<List<Integer>> allPathsSourceTarget(int[][] graph) {
    g = graph;
    n = graph.length;
    List<Integer> list = new ArrayList<>();
    return dfs(0);
}
public List<List<Integer>> dfs( int num) {
    if (cache.containsKey(num)){
        return cache.get(num);
    }
    List<List<Integer>> res = new ArrayList<>();
    if (num == n-1){
        List<Integer> cur = new ArrayList<Integer>(){{add(num);}};
        res.add(cur);
    }else{
        for (int temp: g[num]
        ) {
            for (List<Integer> next: dfs(temp)
                 ) {
                List<Integer> cur = new ArrayList<>(next);
                cur.add(0,num);
                res.add(cur);
            }
        }
    }
    cache.put(num,res);
    return res;
}
  • 时间复杂度O(n2n)O(n*2^{n})
  • 空间复杂度O(n2n)O(n*2^{n})