• LeetCode——课程表 i-ii


    Q:你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-1 。
    在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]
    给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习?

    示例 1:
    输入: 2, [[1,0]]
    输出: true
    解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。
    示例 2:
    输入: 2, [[1,0],[0,1]]
    输出: false
    解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成​课程 0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。
     
    提示:
    输入的先决条件是由 边缘列表 表示的图形,而不是 邻接矩阵 。详情请参见图的表示法。
    你可以假定输入的先决条件中没有重复的边。(1 <= numCourses <= 10^5)

    A:
    这个题说那么多,实际上就是判断有没有环
    1.BFS:队列模拟拓扑排序。

    public boolean canFinish(int numCourses, int[][] prerequisites) {
            if (numCourses <= 1 || prerequisites.length <= 1)
                return true;
            int[] rudu = new int[numCourses];//存入度
            for (int[] prerequisite : prerequisites) {
                rudu[prerequisite[1]]++;
            }
            Queue<Integer> q = new LinkedList<>();//队列里存的是入度为0的点
            for (int i = 0; i < numCourses; i++) {
                if (rudu[i] == 0)
                    q.add(i);
            }
            if (q.isEmpty())
                return false;
            int count = 0;
            while (!q.isEmpty()) {
                int temp = q.poll();
                count++;
                for (int[] prerequisite : prerequisites) {
                    if (prerequisite[0] == temp) {
                        int curr = prerequisite[1];
                        rudu[curr]--;//删除该入度为0的点时,
                        if (rudu[curr] == 0)
                            q.add(curr);
                    }
                }
            }
            return count == numCourses;
        }
    

    2.DFS
    这里设计一个flag:

    1. flag = 0,未被读取过;
    2. flag = -1,当前路径读取,如果当前路径再次读取,说明有环;
    3. flag = 1,之前被别的路径读取过,不需要再读取了,这步是剪枝的过程。
        private int[] flag;
    
        public boolean canFinish(int numCourses, int[][] prerequisites) {
            if (numCourses <= 1 || prerequisites.length <= 1)
                return true;
            flag = new int[numCourses];
            Arrays.fill(flag, 0);
            for (int[] prerequisite : prerequisites) {
                if (flag[prerequisite[0]] == 0) {//未被读取过
                    boolean f = DFS(prerequisite[0], prerequisites);
                    if (!f)
                        return false;
                }
            }
            return true;
        }
    
        private boolean DFS(int i, int[][] prerequisites) {
            flag[i] = -1;//当前路径被读取
            boolean f = true;
            for (int[] prerequisite : prerequisites) {
                if (prerequisite[0] == i) {
                    if (flag[prerequisite[1]] == 0) {//从来未被读取
                        f = DFS(prerequisite[1], prerequisites);
                    } else if (flag[prerequisite[1]] == -1) {//当前路径又一次被读取
                        f = false;
                    }
                }
                if (!f)
                    return false;
            }
            flag[i] = 1;//进入下一次之前,这已经变成前一次的路径了
            return true;
        }
    

    Q:现在你总共有 n 门课需要选,记为 0 到 n-1。
    在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]
    给定课程总量以及它们的先决条件,返回你为了学完所有课程所安排的学习顺序。
    可能会有多个正确的顺序,你只要返回一种就可以了。如果不可能完成所有课程,返回一个空数组。

    示例 1:
    输入: 2, [[1,0]]
    输出: [0,1]
    解释: 总共有 2 门课程。要学习课程 1,你需要先完成课程 0。因此,正确的课程顺序为 [0,1] 。
    示例 2:
    输入: 4, [[1,0],[2,0],[3,1],[3,2]]
    输出: [0,1,2,3] or [0,2,1,3]
    解释: 总共有 4 门课程。要学习课程 3,你应该先完成课程 1 和课程 2。并且课程 1 和课程 2 都应该排在课程 0 之后。
      因此,一个正确的课程顺序是 [0,1,2,3] 。另一个正确的排序是 [0,2,1,3] 。
    说明:
    输入的先决条件是由边缘列表表示的图形,而不是邻接矩阵。详情请参见图的表示法。
    你可以假定输入的先决条件中没有重复的边。

    A:
    同为拓扑排序。
    1.BFS

    public int[] findOrder(int numCourses, int[][] prerequisites) {
            int[] result = new int[numCourses];
            if (numCourses <= 1)
                return new int[numCourses];
            int[] rudu = new int[numCourses];
            for (int[] prerequisite : prerequisites) {
                rudu[prerequisite[1]]++;
            }
            Queue<Integer> q = new LinkedList<>();
            for (int i = 0; i < numCourses; i++) {
                if (rudu[i] == 0)
                    q.add(i);
            }
            if (q.isEmpty())
                return new int[0];
            int count = numCourses-1;
            while (!q.isEmpty()) {
                int temp = q.poll();
                result[count] = temp;
                count--;
                for (int[] prerequisite : prerequisites) {
                    if (prerequisite[0] == temp) {
                        int curr = prerequisite[1];
                        rudu[curr]--;
                        if (rudu[curr] == 0)
                            q.add(curr);
                    }
                }
            }
            if (count != -1)//注意count需要判断是否为-1
                return new int[0];
            return result;
        }
    

    2.DFS

        private int[] flag;
        private ArrayList<Integer> res;
    
        public int[] findOrder(int numCourses, int[][] prerequisites) {
            if (numCourses <= 1)
                return new int[numCourses];
            res = new ArrayList<>();
            flag = new int[numCourses];
            Arrays.fill(flag, 0);
            for (int i = 0; i < numCourses; i++) {
                if (flag[i] == 0) {//这里和前面不一样,是因为如果有独立的点,一定要放进去,所以每个点都要读
                    boolean f = DFS(i, prerequisites);
                    if (!f)
                        return new int[0];
                }
            }
            int[] result = new int[numCourses];
            for (int i = 0; i < numCourses; i++) {
                result[i] = res.get(i);
            }
            return result;
        }
    
        private boolean DFS(int i, int[][] prerequisites) {
            flag[i] = -1;
            boolean f = true;
            for (int[] prerequisite : prerequisites) {
                if (prerequisite[0] == i) {
                    if (flag[prerequisite[1]] == 0) {
                        f = DFS(prerequisite[1], prerequisites);
                    } else if (flag[prerequisite[1]] == -1) {
                        f = false;
                    }
                }
                if (!f)
                    return false;
            }
            flag[i] = 1;
            res.add(i);//这样才能逆着放入结果中
            return true;
        }
    
  • 相关阅读:
    [CF864F]Cities Excursions
    [AGC012F]Prefix Median
    [TC-FindingFriends]Finding Friends
    [TC-HouseProtection]House Protection
    [CTSC2018]假面
    [CF877F]Ann and Books
    [CF509F]Progress Monitoring
    [CF735E/736C]Ostap and Tree
    CF611H New Year and Forgotten Tree
    CF538H Summer Dichotomy
  • 原文地址:https://www.cnblogs.com/xym4869/p/12856520.html
Copyright © 2020-2023  润新知