欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

力扣课程表1-3 java实现

程序员文章站 2022-07-16 09:58:19
...

三道课程表题,前两道与拓扑排序相关,第三道题与优先队列的贪心算法有关。

课程表Ⅰ

力扣课程表1-3 java实现
思路
拓扑排序的话可以考虑用广度优先搜索的方法,判断图是否有环。
一门课有先修课程,说明这门课是有入度的,可以从这一点入手。
构造邻接表来存储图,利用入度矩阵存储每个节点的入度,将入度为0的节点一次入队,然后遍历,减少其对应端点的入度,最后判断是否全部入队。

public boolean canFinish(int numCourses, int[][] prerequisites) {
        int []degrees=new int[numCourses];//入度矩阵
        List<List<Integer>> graph=new ArrayList<>();
        Queue<Integer> queue=new LinkedList<>();
   		//初始化图
        for(int i=0;i<numCourses;i++){
            graph.add(new ArrayList<>());
        }
        for(int []temp:prerequisites){
            degrees[temp[0]]++;
            graph.get(temp[1]).add(temp[0]);//构建图
        }
        //入度为0的课程入队
        for(int i=0;i<numCourses;i++){
            if(degrees[i]==0)
                queue.add(i);
        }
        while(!queue.isEmpty()){
            int temp=queue.poll();
            numCourses--;
            for(int cur:graph.get(temp)){
                if(--degrees[cur]==0)
                    queue.add(cur);
            }
        }
        return numCourses==0;
    }

课程表Ⅱ

力扣课程表1-3 java实现
思路
这里的思路与上一题类似,因为要输出课程顺序,所以多了一个存储步骤。

public int[] findOrder(int numCourses, int[][] prerequisites) {
		int []res=new int[numCourses];//存储学习顺序
        int []degrees=new int[numCourses];
        List<List<Integer>> graph=new ArrayList<>();
        Queue<Integer> queue =new LinkedList<>();
        for(int i=0;i<numCourses;i++){
            graph.add(new ArrayList<>());
        }
        for(int [] temp:prerequisites){
            degrees[temp[0]]++;
            graph.get(temp[1]).add(temp[0]);
        }
        for(int i=0;i<numCourses;i++){
            if(degrees[i]==0)
                queue.add(i);
        }
        int count=0;
        while(!queue.isEmpty()){
            int temp=queue.poll();
            res[count++]=temp;
            for(int cur:graph.get(temp)){
                if(--degrees[cur]==0)
                    queue.add(cur);
            }
        }
        return count==numCourses?res:new int[]{};
    }

PS:这两题还有一个方式不使用ArrayList实现,但是实现代价却会更高,主要是在修改课程入度的时候做了变化,在这里贴出主要代码供大家参考。

			// 修改节点入度
            for(int[] edge : prerequisites) {
                if (edge[1] == temp) {
                    degrees[edge[0]]--;
                    if (degrees[edge[0]] == 0) {
                        queue.offer(edge[0]);
                    }
                }
            }

课程表Ⅲ

力扣课程表1-3 java实现
思路
这一题要求得出最多能修几门课程,应该能想到贪心算法的思想,这里有一个课程耗费跟课程结束时间,不过优先队列我确实没有首先想到,看了思路之后才发现优先队列+贪心算法的结合已经很可了…(看到有基于贪心算法的堆排序实现的,好像效果也很不错)

public int scheduleCourse(int[][] courses) {
        //根据课程结束时间升序排列
        Arrays.sort(courses,(a,b) -> (a[1]-b[1]));
        //课程用时的大根优先级队列
        PriorityQueue<Integer> queue = new PriorityQueue<>((a,b) -> (b-a));
        int time = 0;
        for (int[] temp: courses) {
            //如果不能学习此课程,因为此课程结束时间比之前所有的都晚,存在两种情况:
            //1.此课程用时比之前某个课程少:则学习此课程,放弃之前用时最长的课程
            //2.此课程用时比之前所有课程多:则不学习此课程,可以理解为学习此课程,同时放弃之前用时最长的课程
            if (time + temp[0] <= temp[1]) {
                queue.offer(temp[0]);
                time += temp[0];
            } else if (!queue.isEmpty() && queue.peek() > temp[0]) {
                time += temp[0] - queue.poll();
                queue.offer(temp[0]);
            }
        }
        return queue.size();
    }