【算法】【线性表】【数组】课程表

1  题目

你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。

在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程  bi 。

  • 例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。

请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。

示例 1:

输入:numCourses = 2, prerequisites = [[1,0]]
输出:true
解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。

示例 2:

输入:numCourses = 2, prerequisites = [[1,0],[0,1]]
输出:false
解释:总共有 2 门课程。学习课程 1 之前,你需要先完成​课程 0 ;并且学习课程 0 之前,你还应先完成课程 1 。这是不可能的。

提示:

  • 1 <= numCourses <= 2000
  • 0 <= prerequisites.length <= 5000
  • prerequisites[i].length == 2
  • 0 <= ai, bi < numCourses
  • prerequisites[i] 中的所有课程对 互不相同

2  解答

这道题主要就是判断是否存在死循环,第一次我递归这么写的:

复制代码
class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        // 为空或者就一个直接返回
        if (prerequisites == null || prerequisites.length <= 1) {
            return true;
        }
        Map<Integer, List<Integer>> map = new HashMap<>(prerequisites.length);
        for (int[] prerequisite : prerequisites) {
            List<Integer> list = map.computeIfAbsent(prerequisite[0], (a) -> new ArrayList<>());
            list.add(prerequisite[1]);
        }
        for (int[] prerequisite : prerequisites) {
            Set<Integer> sets = new HashSet<>();
            sets.add(prerequisite[0]);
            boolean res = chargeRecursion(sets, map, prerequisite[1]);
            if (res) {
                return false;
            }
        }
        return true;
    }

    private static boolean chargeRecursion(Set<Integer> way, Map<Integer, List<Integer>> map, Integer current) {
         if (Objects.isNull(current)) {
            return false;
        }
        if (way.contains(current)) {
            return true;
        }
        List<Integer> list = map.get(current);
        if (list == null || list.size() <= 0) {
            return false;
        }
        for (Integer item : list) {
            // 只要有一个循环就返回false
            Set<Integer> sets = new HashSet<>(way);
            sets.add(current);
            boolean itemRes = chargeRecursion(sets, map, item);
            if (itemRes) {
                return true;
            }
        }
        return false;
    }
}
复制代码

有个 2000 的测试用例超时了,然后我加了一个 Set 如果这个课程判断过了,就不需要再递归了,我修改完的如下:

复制代码
class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        // 为空或者就一个直接返回
        if (prerequisites == null || prerequisites.length <= 1) {
            return true;
        }
        Set<Integer> alreadyGet = new HashSet<>();
        // 表示该课程的前课程
        Map<Integer, List<int[]>> inMap = Arrays.stream(prerequisites).collect(Collectors.groupingBy(i -> i[0]));
        for (int i = 1; i <= numCourses; i++) {
            List<int[]> list = inMap.get(i);
            // 表示该课程没要前置的课程,略过
            if (Objects.isNull(list)) {
                continue;
            }
            // 如果已经可以得到该课程了 直接略过
            if (alreadyGet.contains(i)) {
                continue;
            }
            // 有前置的看每个课程都能学到么
            for (int[] cur : list) {
                Set<Integer> sets = new HashSet<>();
                sets.add(cur[0]);
                boolean chargeGet = chargeGet(inMap, alreadyGet, sets, cur[1]);
                if (!chargeGet) {
                    return false;
                }
            }
            alreadyGet.add(i);
        }
        return true;
    }

    private static boolean chargeGet(Map<Integer, List<int[]>> inMap, Set<Integer> alreadyGet, Set<Integer> way, int current) {
        List<int[]> list = inMap.get(current);
        if (list == null || list.size() <= 0) {
            return true;
        }
        if (alreadyGet.contains(current)) {
            return true;
        }
        for (int[] item : list) {
            if (way.contains(item[1])) {
                return false;
            }
            Set<Integer> sets = new HashSet<>(way);
            sets.add(item[0]);
            boolean itemRes = chargeGet(inMap, alreadyGet, sets, item[1]);
            if (!itemRes) {
                return false;
            }
        }
        alreadyGet.add(current);
        return true;
    }
}
复制代码

哈哈哈,虽然过了,但是打败的人是不是太少了。。。。我空了得再寻思寻思。

加油。

posted @   酷酷-  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
历史上的今天:
2023-03-18 【InheritableThreadLocal】InheritableThreadLocal的实现机制和原理
点击右上角即可分享
微信分享提示