拓扑排序类题目

1.课程安排的合法性

力扣传送门
题目:
你这个学期必须选修 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。这是不可能的。

/*
    * 题目描述:一个课程可能会先修课程,判断给定的先修课程规定是否合法。
    * 本题不需要使用拓扑排序,只需要检测有向图是否存在环即可。
    * */
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        List<Integer> pre[] = new List[numCourses];//pre[i]中存储着修习课程i之前要修习哪些课
        for(int i=0;i<numCourses;i++){
            pre[i]=new LinkedList<>();
        }
        for (int i = 0; i < prerequisites.length; i++) {
            pre[prerequisites[i][0]].add(prerequisites[i][1]);
        }
        //判断顺序是否合理,如果有环就不合理
        boolean localvisit[] = new boolean[numCourses];
        boolean globalvisit[] = new boolean[numCourses];
        for (int i = 0; i < numCourses; i++) {
            if (!rational(pre, i, localvisit, globalvisit)) return false;
        }
        return true;
    }

    //判断顺序是否合理,如果有环就不合理
    public boolean rational(List<Integer> pre[], int cur, boolean localvisit[], boolean globalvisit[]) {
        if (localvisit[cur]) return false;
        if (globalvisit[cur]) return true;
        localvisit[cur] = true;
        globalvisit[cur] = true;
        for(int elem:pre[cur]){
            if(!rational(pre,elem,localvisit,globalvisit)) return false;
        }
        localvisit[cur]=false;
        return true;
    }

2.课程安排的顺序

力扣传送门
现在你总共有 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] 。

    /*
    * 找到一个合理的课程安排的顺序
    * */
    public int[] findOrder(int numCourses, int[][] prerequisites) {
        List<Integer> pre[]=new List[numCourses];
        Stack<Integer> courses=new Stack<>();
        for(int i=0;i<numCourses;i++){
            pre[i]=new LinkedList<>();
        }
        for(int i=0;i<prerequisites.length;i++){
            pre[prerequisites[i][0]].add(prerequisites[i][1]);
        }
        boolean localvisit[]=new boolean[numCourses];
        boolean globalvisit[]=new boolean[numCourses];
        for(int cur=0;cur<numCourses;cur++){
            if(!isRational(pre,cur,localvisit,globalvisit,courses)) return new int[0];
        }
        int[] orders = new int[numCourses];
        for (int i = numCourses - 1; i >= 0; i--) {
            orders[i] = courses.pop();
        }
        return orders;
    }
    public boolean isRational(List<Integer> preCourses[],int cur,boolean localvisit[],boolean globalvisit[],Stack<Integer> courses){
        if(localvisit[cur]) return false;//在当此课程顺序中 是否已经安排了cur,如果已经安排则存在环,是不合理的
        if(globalvisit[cur]) return true;//在已经遍历过的所有顺序中,是否已经访问过了cur,说明已经被判断过“为cur安排之前的课程”不会存在环了
        localvisit[cur]=true;
        globalvisit[cur]=true;
        for(int pre:preCourses[cur]){
            if(!isRational(preCourses,pre,localvisit,globalvisit,courses)) return false;
        }
        courses.push(cur);//先存入当前课之前需要安排的课程
        localvisit[cur]=false;
        return true;
    }
发布了184 篇原创文章 · 获赞 60 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/StubbornAccepted/article/details/105204989
今日推荐