力扣labuladong一刷day44天环检测与拓扑排序

本文介绍了力扣平台上的两道关于课程表的算法题目,分别是判断有向图是否存在环(207题)和无环时进行拓扑排序(210题),涉及深度优先遍历、回溯和邻接表的构建。

力扣labuladong一刷day44天环检测与拓扑排序

一、207. 课程表

题目链接:https://leetcode.cn/problems/course-schedule/
思路:简单来说就是判断有向图是否有环,如果有环就无法完成课程。要遍历图首先构建邻接表,即buildGraph,然后进行遍历,采用深度优先遍历,需要借助一个标记数组,来到过当前节点即标记,这就解决了遍历问题了。其次是解决是否有环的问题,可以借助回溯的思想,进入节点进行标记,离开节点取消标记,没有环是正常的,可以随着遍历走遍全树,如果当前节点被标记则说明有环,因为还没有回溯离开把节点标记取消,就遇到了,说明有环。

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

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

    void traverse(List<Integer>[] graph, int i) {
        if (onPaths[i]) {
            hasCycle = true;
        }
        if (visited[i] || hasCycle) {
            return;
        }
        onPaths[i] = true;
        visited[i] = true;
        for (Integer j : graph[i]) {
            traverse(graph, j);
        }
        onPaths[i] = false;
    }

    // 构建邻接表
    List<Integer>[] buildGraph(int numCourses, int[][] prerequisites) {
        List<Integer>[] graph = new ArrayList[numCourses];
        for (int i = 0; i < numCourses; i++) {
            graph[i] = new ArrayList<>();
        }
        for (int[] ints : prerequisites) {
            graph[ints[1]].add(ints[0]);
        }
        return graph;
    }
}

二、210. 课程表 II

题目链接:https://labuladong.github.io/algo/di-yi-zhan-da78c/shou-ba-sh-03a72/huan-jian–e36de/
思路:上一题是让求有环还是无环,本题是如果没有环返回拓扑排序,那么其实拓扑排序就是后序遍历翻转之后的结果,当我们在构建图的时候,也可以理解为构建树的时候,将箭头指向反过来则无需翻转后序遍历结果。

class Solution {
   boolean[] visited;
    boolean[] onPaths;
    boolean hasCycle;
    List<Integer> list;
    public int[] findOrder(int numCourses, int[][] prerequisites) {
        visited = new boolean[numCourses];
        onPaths = new boolean[numCourses];
        list = new ArrayList<>();
        List<Integer>[] graph = buildGraph(numCourses, prerequisites);
        for (int i = 0; i < numCourses; i++) {
            travers(graph, i);
        }
        if (hasCycle) {
            return new int[]{};
        }
        int[] res = new int[numCourses];
        for (int i = 0; i < list.size(); i++) {
            res[i] = list.get(i);
        }
        return res;
    }

    void travers(List<Integer>[] graph, int i) {
        if (onPaths[i]) {
            hasCycle = true;
        }
        if (visited[i] || hasCycle) {
            return;
        }
        onPaths[i] = true;
        visited[i] = true;
        for (Integer j : graph[i]) {
            travers(graph, j);
        }
        list.add(i);
        onPaths[i] = false;
    }


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

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

当年拼却醉颜红

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值