(Leetcode)判断一个图是否是可以拓扑排序的——使用Queue

207. Course Schedule

拓扑排序 Topological Order

对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。
通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。
简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。

There are a total of n courses you have to take, labeled from 0 to n – 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?

For example:

2, [[1,0]]

There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible.

2, [[1,0],[0,1]]

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.

分析

  1. 通过计算所有点的inDegree(入度),找到拓扑序列中可能是开头的点(inDegree[node]==0)。将这些点加入队列queue。
  2. 遍历队列,对每一个队列中的点cur_node:
    找到他的一个post_node,并将inDegree[post_node]- –
    如果inDegree[post_node]==0 ,把post_node也加入队列。
  3. 遍历所有inDegree,如果inDegree[node]!=0。说明图中有环,说明有node没有被加入queue。
    (那只可能是因为这个node在他的pre_node还没被访问到的时候,就被访问了。)

Code

public class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        if (numCourses <= 0) return false;
        Queue<Integer> queue = new LinkedList<Integer>(); //LinkedList实现了Queue接口
        int inDegree[] = new int[numCourses];
        for(int i=0; i<prerequisites.length; i++){
            inDegree[prerequisites[i][1]]++;
        }
        for(int i=0; i<numCourses; i++){
            if(inDegree[i]==0){// this node don't have prenode
                queue.offer(i);
            }
        }
        Integer curNode;
        while((curNode = (Integer)queue.poll())!=null){
            for(int i=0; i<prerequisites.length; i++){
                if(prerequisites[i][0]==curNode){
                    inDegree[prerequisites[i][1]]--;
                    if(inDegree[prerequisites[i][1]]==0){
                        queue.offer(prerequisites[i][1]);
                    }
                }
            }
        }

        for(int i=0; i<numCourses; i++){
            if(inDegree[i]!=0) return false;
        }
        return true;
    }
}

java Queue中 remove/poll, add/offer, element/peek区别

offer,add区别:

一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,多出的项就会被拒绝。
这时新的 offer 方法就可以起作用了。它不是对调用 add() 方法抛出一个 unchecked 异常,而只是得到由 offer() 返回的 false。

poll,remove区别:

remove() 和 poll() 方法都是从队列中删除第一个元素。remove() 的行为与 Collection 接口的版本相似,
但是新的 poll() 方法在用空集合调用时不是抛出异常,只是返回 null。因此新的方法更适合容易出现异常条件的情况。

peek,element区别:

element() 和 peek() 用于在队列的头部查询元素。与 remove() 方法类似,在队列为空时, element() 抛出一个异常,而 peek() 返回 null

    原文作者:拓扑排序
    原文地址: https://blog.csdn.net/muyu709287760/article/details/53457865
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞