图论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(); // 回溯,移除当前节点,继续搜索其他邻居
        }
    }
}
相关推荐
Cosolar4 小时前
极简智库:快速搭建你的开源项目教程阅读平台,让 docs/ 目录被更多人看见
java·架构·github
nice_lcj5204 小时前
【从零理解 Spring AI · 16】Agent 与工作流:什么该写死,什么该让模型决定
java·人工智能·后端·spring ai·ai应用开发
北京云帆互联科技5 小时前
云帆培训考试系统更新说明:v9.3.0
java·学习
学长毕设6 小时前
基于SpringBoot的景点管理系统-附源码
java·spring boot·后端
sxlishaobin7 小时前
Maven Setting详解
java·学习·maven
知守观7 小时前
一个方法两个触发口:反编译 XXL-Job 后,我看清了 inner/job 子包的裸奔现状
java·spring boot·微服务
用户3126874877207 小时前
CompletableFuture 链式编排:异步编程的优雅解法
java
瑞雪兆丰年兮7 小时前
JavaWeb-day14-SpringBootWeb原理篇
java·开发语言·spring boot·spring·bean·mybatis·javaweb
神仙别闹7 小时前
基于 Java GUI 贪心策略直接搜索算法和极大极小博弈树算法的智能人机博弈五子棋游戏
java·毕业设计·gui·贪心策略·极大极小博弈树
Flynn Liang8 小时前
RAG 评估体系:黄金集、检索指标与 LLM-as-Judge 落地
java·langchain·rag·评估·langchain4j·检索指标