图论03-所有可能路径(Java)

3.所有可能路径

  • 题目描述

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

graph[i] 是一个从节点 i 可以访问的所有节点的列表(即从节点 i 到节点 graph[i][j]存在一条有向边)。

示例 1:

java 复制代码
输入:graph = [[1,2],[3],[3],[]]
输出:[[0,1,3],[0,2,3]]
解释:有两条路径 0 -> 1 -> 3 和 0 -> 2 -> 3
  • 题目分析
java 复制代码
具体解题思路如下:
创建一个数组 used 用于标记节点是否被遍历过,初始化为0。
将源节点 0 加入初始路径,并调用 dfs 函数开始深度优先搜索。
在 dfs 函数中,首先判断当前节点是否为目标节点,如果是,则将当前路径添加到结果中,并标记当前节点未被访问过,然后返回。
如果当前节点不是目标节点,遍历当前节点可到达的所有节点,如果该节点未被访问过,则将节点加入当前路径,以该节点为起点继续递归调用 dfs 函数。在递归调用结束后,需要进行回溯操作,即移除最后一个节点,尝试其他路径。
这样就可以找出所有从源节点到目标节点的路径,并将其存储在 result 中。
  • Java代码分析

深度优先遍历(使用used数组)

java 复制代码
import java.util.LinkedList;
import java.util.List;
import java.util.ArrayList;

public class Solution {
    // 用于存储当前路径的节点
    LinkedList<Integer> path = new LinkedList<>();
    // 存储所有符合条件的路径
    List<List<Integer>> result = new ArrayList<>();

    // 主函数,找出从源节点到目标节点的所有路径
    public List<List<Integer>> allPathsSourceTarget(int[][] graph) {
        // 创建一个数组,用于标记节点是否被遍历
        int[] used = new int[graph.length];
        path.add(0); // 将源节点加入初始路径
        dfs(graph, used, 0); // 开始深度优先搜索
        return result; // 返回所有路径
    }

    // 深度优先搜索函数
    private void dfs(int[][] graph, int[] used, int startNode) {
        // 如果当前节点为目标节点,将当前路径添加到结果中
        if (startNode == graph.length - 1) {
            result.add(new ArrayList<>(path));
            used[startNode] = 0; // 标记当前节点未被访问
            return;
        }

        // 遍历当前节点可到达的所有节点
        for (int i = 0; i < graph[startNode].length; i++) {
            // 如果该节点未被访问过,继续深度优先搜索
            if (used[graph[startNode][i]] == 0) {
                path.add(graph[startNode][i]); // 将节点加入当前路径
                dfs(graph, used, graph[startNode][i]); // 以该节点为起点继续搜索
                path.removeLast(); // 回溯,移除最后一个节点,尝试其他路径
            }
        }
    }
}

为什么此题可以不使用used数组?

md 复制代码
这是因为在深度优先搜索中,我们使用了路径 path 来记录当前的访问状态,每次递归调用都会将当前节点加入路径,并在递归结束后将其移出路径。这样就不需要额外的 used 数组来标记节点是否被访问过,因为路径 path 本身已经隐式地记录了节点的访问状态。
当我们尝试访问一个节点时,首先会检查该节点是否已经在当前路径中,如果在,则说明形成了环路,不再继续访问;如果不在,则将该节点加入路径,并继续向下递归。在每一次递归结束后,我们会将最后一个节点从路径中移出,这样就能够正确地模拟节点的访问状态,而不需要额外的 used 数组来记录。
java 复制代码
import java.util.LinkedList;
import java.util.List;
import java.util.ArrayList;

public class AllPathsSourceTarget {
    LinkedList<Integer> path = new LinkedList<>(); // 用于存储当前路径的节点序列
    List<List<Integer>> result = new ArrayList<>(); // 存储所有从起点到终点的路径

    // 主方法,返回所有从起点到终点的路径
    public List<List<Integer>> allPathsSourceTarget(int[][] graph) {
        path.add(0); // 将起点添加到路径中
        dfs(graph, 0); // 开始深度优先搜索
        return result; // 返回所有路径结果
    }

    // 深度优先搜索方法
    private void dfs(int[][] graph, int x) {
        // 判断是否到达终点
        if (x == graph.length - 1) {
            result.add(new ArrayList<>(path)); // 将当前路径添加到结果中
            return;
        }

        // 遍历当前节点的邻居节点
        for (int i = 0; i < graph[x].length; i++) {
            int node = graph[x][i]; // 获取邻居节点
            path.add(node); // 将邻居节点加入路径中
            dfs(graph, node); // 递归搜索邻居节点
            path.removeLast(); // 回溯,移除当前节点,继续搜索其他邻居
        }
    }
}
相关推荐
Hello-Brand4 分钟前
Java核心知识体系10-线程管理
java·高并发·多线程·并发·多线程模型·线程管理
乐悠小码10 分钟前
数据结构------队列(Java语言描述)
java·开发语言·数据结构·链表·队列
史努比.12 分钟前
Pod控制器
java·开发语言
2的n次方_14 分钟前
二维费用背包问题
java·算法·动态规划
皮皮林55115 分钟前
警惕!List.of() vs Arrays.asList():这些隐藏差异可能让你的代码崩溃!
java
莳光.15 分钟前
122、java的LambdaQueryWapper的条件拼接实现数据sql中and (column1 =1 or column1 is null)
java·mybatis
程序猿麦小七20 分钟前
基于springboot的景区网页设计与实现
java·spring boot·后端·旅游·景区
weisian15126 分钟前
认证鉴权框架SpringSecurity-2--重点组件和过滤器链篇
java·安全
蓝田~28 分钟前
SpringBoot-自定义注解,拦截器
java·spring boot·后端
.生产的驴30 分钟前
SpringCloud Gateway网关路由配置 接口统一 登录验证 权限校验 路由属性
java·spring boot·后端·spring·spring cloud·gateway·rabbitmq