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

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 @ 2024-03-18 10:58  酷酷-  阅读(30)  评论(0)    收藏  举报