图论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(); // 回溯,移除当前节点,继续搜索其他邻居
        }
    }
}
相关推荐
南山十一少1 小时前
Spring Security+JWT+Redis实现项目级前后端分离认证授权
java·spring·bootstrap
427724002 小时前
IDEA使用git不提示账号密码登录,而是输入token问题解决
java·git·intellij-idea
chengooooooo3 小时前
苍穹外卖day8 地址上传 用户下单 订单支付
java·服务器·数据库
李长渊哦3 小时前
常用的 JVM 参数:配置与优化指南
java·jvm
计算机小白一个3 小时前
蓝桥杯 Java B 组之设计 LRU 缓存
java·算法·蓝桥杯
南宫生6 小时前
力扣每日一题【算法学习day.132】
java·学习·算法·leetcode
计算机毕设定制辅导-无忧学长6 小时前
Maven 基础环境搭建与配置(一)
java·maven
风与沙的较量丶7 小时前
Java中的局部变量和成员变量在内存中的位置
java·开发语言
m0_748251727 小时前
SpringBoot3 升级介绍
java
极客先躯8 小时前
说说高级java每日一道面试题-2025年2月13日-数据库篇-请说说 MySQL 数据库的锁 ?
java·数据库·mysql·数据库的锁·模式分·粒度分·属性分