剑指offer113:课程顺序

题目:
现在总共有 numCourses 门课需要选,记为 0 到 numCourses-1。
给定一个数组 prerequisites ,它的每一个元素 prerequisites[i] 表示两门课程之间的先修顺序。 例如 prerequisites[i] = [ai, bi] 表示想要学习课程 ai ,需要先完成课程 bi 。
请根据给出的总课程数 numCourses 和表示先修顺序的 prerequisites 得出一个可行的修课序列。
可能会有多个正确的顺序,只要任意返回一种就可以了。如果不可能完成所有课程,返回一个空数组。
示例一:
输入: numCourses = 2, prerequisites = [[1,0]]
输出: [0,1]
解释: 总共有 2 门课程。要学习课程 1,你需要先完成课程 0。因此,正确的课程顺序为 [0,1] 。

示例二:
输入: numCourses = 4, prerequisites = [[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] 。

示例三:
输入: numCourses = 1, prerequisites = []
输出: [0]
解释: 总共 1 门课,直接修第一门课就可。
分析:
将课程看成图中节点,如果两门课程存在先修顺序那么它们在图中对应的节点之间存在一条先修课程和后修课程的边,因此这是一个有向图。
numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]]构建的有向图如下图
在这里插入图片描述
可行的修课序列实际上是图的拓扑排序序列,图中的每条边都是从先修课程指向后修课程,而拓扑排序能够保证任意一条边的起始节点一定排在终止节点的前面,因此拓扑排序得到的序列与先修顺序一定不会存在冲突,于是这个问题转变成如何求有向图的拓扑排序序列。
该题使用拓扑排序算法。
具体细节详细见代码。
代码:

package com.kuang;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class FindOrder {
    public int[] findOrder(int numCourses, int[][] prerequisites) {
//        先创建一个邻接表,键是先修课程,值是必须在键对应的课程之后学习的所有课程
        HashMap<Integer, List<Integer>> graph = new HashMap<>();
        for (int i = 0; i < numCourses; i++) {
            graph.put(i,new LinkedList<Integer>());
        }
//        将每个节点的入度保存到数组inDegrees中
        int[] inDegrees = new int[numCourses];
        for (int[] preq:prerequisites){
            graph.get(preq[1]).add(preq[0]);
//            preq[0]节点入度加1
            inDegrees[preq[0]]++;
        }
        Queue<Integer> queue = new LinkedList<>();
        for (int i = 0; i < numCourses; i++) {
            if (inDegrees[i] ==0){
                queue.add(i);
            }
        }
        List<Integer> order = new LinkedList<>();
        while (!queue.isEmpty()){
           int course = queue.remove();
           order.add(course);
           for (int next:graph.get(course)){
               inDegrees[next]--;
               if (inDegrees[next]==0){
                   queue.add(next);
               }
           }
        }
        return order.size() == numCourses ?order.stream().mapToInt(i->i).toArray():new int[0];
    }
}

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙崎流河

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值