算法之图类经典问题

该文介绍了如何使用深度优先遍历(DFS)和广度优先遍历(BFS)解决LeetCode第207题——课程表的问题。通过构建有向图,检查是否存在环来判断课程能否按顺序完成。代码示例给出了Java实现,包括DFS和BFS两种方法,并提到了拓扑排序的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

LeetCode原题

 207. 课程表,链接: link

解题思路

  • 1.深度优先遍历DFS
    • 抽象构建成一个有向图(邻接表,或邻接矩阵)
    • 遍历图中每个节点
    • 判断有向图是否有环
  • 2.广度优先遍历BFS。
    • 抽象构建成一个有向图(邻接表,或邻接矩阵)
    • 构建一个数组记录每个节点的入度
    • 对 BFS 队列进行初始化,将入度为 0 的节点首先装入队列
    • 开始执行 BFS 循环,不断弹出队列中的节点,减少相邻节点的入度,并将入度变为 0 的节点加入队列
    • 如果最终所有节点都被遍历过(count 等于节点数),则说明不存在环,反之则说明存在环

代码

Java

class Solution {
    // 思路1:DFS
    // 记录遍历过的节点,防止走回头路
    boolean[] visited;
    // 记录一次递归堆栈中的节点
    boolean[] onPath;
    // 记录图中是否有环
    boolean hasCycle = false;

    public boolean canFinish(int numCourses, int[][] prerequisites) {
        List<Integer>[] graph = buildGraph(numCourses, prerequisites);
        visited = new boolean[numCourses];
        onPath = new boolean[numCourses];

        for (int i = 0; i < numCourses; i++) {
            traverse(graph, i);
        }
        return !hasCycle;
    }

    public void traverse(List<Integer>[] graph, int s) {
        // base case
        if (onPath[s]) {
            hasCycle = true;
        }
        if (visited[s] || hasCycle) {
            return;
        }

        visited[s] = true;
        onPath[s] = true;
        for (int t : graph[s]) {
            traverse(graph, t);
        }
        onPath[s] = false;
    }

    public List<Integer>[] buildGraph(int numCourses, int[][] prerequisites) {
        List<Integer>[] graph = new LinkedList[numCourses];
        for (int i = 0; i < numCourses; i++) {
            graph[i] = new LinkedList<>();
        }
        for (int[] edge : prerequisites) {
            int from = edge[1], to = edge[0];
            graph[from].add(to);
        }
        return graph;
    }
}

注意要点

  • 细节
    • 抽象图(由节点和边组成,可看做是多叉树)类问题,选择合适的数据结构模型:邻接表(List[] graph;占用空间较少),或邻接矩阵(boolean[][] matrix;占用空间较多,便于直接判断两个节点是否相邻),可通过值来存储权值
    • 遍历和访问(操作):设定visited、onPath数组,来判断是否成环
  • 延伸
    • 若是要获取图的拓扑排序,将后序遍历的结果进行反转,就是拓扑排序的结果

推荐相关

  • 210 课程表 II
  • 797 所有可能的路径
  • 547 省份数量
  • 785 判断二分图
  • 210 课程表 II
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值