刷题用到的拓扑排序是个啥?

先看道题吧

Leetcode207. Course Schedule

There are a total of numCourses courses you have to take, labeled from 0 to numCourses-1.

Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]

Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?

Example 1:

Input: numCourses = 2, prerequisites = [[1,0]]
Output: true
Explanation: There are a total of 2 courses to take. 
             To take course 1 you should have finished course 0. So it is possible.

Example 2:

Input: numCourses = 2, prerequisites = [[1,0],[0,1]]
Output: false
Explanation: There are a total of 2 courses to take. 
             To take course 1 you should have finished course 0, and to take course 0 you should
             also have finished course 1. So it is impossible.

大概意思就是给你一个课程表,你需要去上这些课,但这些课是有依赖关系的。用[0,1]这样的数组表示,要上0号课就先得上1号课。判断能否完成全部课程?我看完是一脸懵逼,看了讨论区的解释,需要用到拓扑排序(Topological sorting)。好吧用自己的话来解释一下。其实就是在有向无环图中,找到一条无重复的路径且有依赖关系的路径。

首先解释一下度的概念,度分为出度和入度。在图中,其他节点指向该节点的是入度,该节点指向其他节点的则是出度。本题中,就是一门课作为另外一门课的前驱,被依赖的则出度为1,依赖的则入读为1如下图

Example Input: numCourses = 4, prerequisites = [[0,3],[1,2],[2,3]]的图如下

这道题可以用Kahn's algorithm解决,将度为0的节点加入队列,然后将其边的节点的度减一,判断节点的入度为0不,为0就加入队列,直到所有节点的入度都为0,如果该图有环则失败。

代码实现

本题可以用LinkedList来存储每个节点的依赖关系,再用一个数组来记录每个每个节点的度,用Queue来实现遍历。具体可以看注释。

class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        //用来统计每个节点的关系
        LinkedList<Integer>[] neigh = new LinkedList[numCourses];
        //队列用来遍历入度为0的节点
        Queue<Integer> queue = new LinkedList<>();
        //节点的入度
        int[] indegree = new int[numCourses];
        //初始化
        for (int i=0; i<numCourses; i++) neigh[i] = new LinkedList<>();

        //建立节点的依赖并将节点的入度加1,比如[0,1]neigh[1].add(1), indegree[0]++
        for (int[] pair : prerequisites) {
            neigh[pair[1]].add(pair[0]);
            indegree[pair[0]]++;
        }

        //入度为0的节点加入队列
        for (int i=0; i<numCourses; i++) {
            if (indegree[i]==0) queue.offer(i);
        }
        
        //用于统计遍历的节点个数
        int count = 0;
        while (!queue.isEmpty()) {
            int course = queue.poll();
            count++;
            //将该节点指向的节点的入度减1,并判断入度是否为0,然后加入队列
            for (int a : neigh[course]) {
                if (--indegree[a] == 0) queue.offer(a); 
            }
        }
        //入度全为0则相等,否则不等
        return count == numCourses;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值