LeetCode207——课程表

https://blog.csdn.net/weixin_42001089/article/details/84327306

定义:

直接copy一下 百科上面的吧:

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

使用的算法也很简单步骤大概就是:这里使用bfs(dfs遍历也可以)

一:先计算所有节点的入度

二:将所有入度为0的点进入一个队列

三:然后出队,得到一个元素

四:将该元素指向的所有元素的入度减1

五:如果减后其入度为0则将该元素入队列

六:继续出队重复步骤三,直到队列为空

还是举个例子吧:

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

假设队列为queue

依据图可以得到每个节点的入度:

{A:0,B:1,C:1,D:2,E:1,F:1,G:1,H:1}

一开始只有入度为0的节点入队即A节点入队

queue= [A]

依次遍历其所有指向元素:

首先是B,将其入度减为0,然后其入度为1-1=0,入度为0入队

queue = [B],然后是E,入度减1为0,入度为0入队queue = [B,E]

此时{A:0,B:0,C:1,D:2,E:0,F:1,G:1,H:1}

为了可视化,上面的入度减一的过程其实可以看成擦除边的过程,即上面这一个循环结束后,拓扑图就变成:

好了,B出队列,其指向的C的入度减一,C的入度为0,进入队列,此时:

queue = [E,C]

{A:0,B:0,C:0,D:2,E:0,F:1,G:1,H:1}

拓扑图变为:

E出队,F入度减一入队

queue = [C,F]

{A:0,B:0,C:0,D:2,E:0,F:0,G:1,H:1}

C出队,首先遍历D,D入度减一变为1,不为0,不如队列,

              接着遍历H,H入度减一变为0,入队列

queue = [F,H]

{A:0,B:0,C:0,D:1,E:0,F:0,G:1,H:0}

F出队,遍历D,D的入度减一变为0,入队列

queue = [H,D]

{A:0,B:0,C:0,D:0,E:0,F:0,G:1,H:0}

H出队列,其没有所指向的元素,直接跳过,此时:

queue = [D]

{A:0,B:0,C:0,D:0,E:0,F:0,G:1,H:0}

D出队列,遍历到G,其入度减一为0,入队

queue = [G]

{A:0,B:0,C:0,D:0,E:0,F:0,G:0,H:0}

G出队列,其没有所指的元素,直接跳过

 

再次出队发现队列为空结束。

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

上述出入队列的顺序就是拓扑排序的顺序即ABECHFDG

还没完呢!!!!!!!!!!!!!!!!!

其实它的更多用途是用来判断有向图是否存在环,当出队的个数等于图节点个数的时候是无环图,相反便是有环图

比如上面出队的个数是8个(ABECHFDG),图上节点也是8个(ABCDEFGH)所以上图就是无环图,为了对比,下面我们再举一个有环图看一下:很明显红圈的部分就是一个环

我们按上面的算法走一下,这里我就不再详细叙述了,直接给出每一步的结果

开始的时候

queue=[A]

{A:0,B:2,C:1,D:1,E:1}

A出队操作后:

queue=[D]

{A:0,B:1,C:1,D:0,E:1}

D出队列,发现没有所指元素,直接跳过

queue=[]

{A:0,B:1,C:1,D:0,E:1}

此时发现队列为空,没有元素可出,结束

 

最后发现出队的元素个数是2(A,D),而图上的个数是5个(ABCDE),两者不相同证明有环,同时注意有环的时候是没有拓扑排序的即没有拓扑排序的

--------------------------------------------------------------------------------------------------------------------------------------------------------------

public boolean canFinish(int numCourses, int[][] prerequisites) {
		int ret = 0;
		Queue<Integer> q = new LinkedList<>();
		if(numCourses <= 1)
			return true;
		int row = prerequisites.length;
		int[] map = new int[numCourses];
		for(int i=0; i<row; i++) {
			map[prerequisites[i][1]]++;
		}
		for(int i=0; i<numCourses; i++) {
			if(map[i] == 0) {
				q.offer(i);
			}
		}
		while(!q.isEmpty()) {
			int target = q.poll();
			ret++;
			for(int i=0; i<row; i++) {
				if(prerequisites[i][0] == target) {
					map[prerequisites[i][1]] --;
					if(map[prerequisites[i][1]] == 0) {
						q.offer(prerequisites[i][1]);
					}
				}
			}
		}
		if(ret == numCourses)
			return true;
		return false;
}

法2:DFS
https://www.cnblogs.com/MrSaver/p/9996941.html

class Solution {
     public boolean canFinish(int numCourses, int[][] prerequisites) {
        ArrayList<ArrayList<Integer>> graph = new ArrayList<>();
        for(int i=0;i<numCourses;i++)
            graph.add(new ArrayList<>());
        for(int i=0;i<prerequisites.length;i++)
        {
            int course = prerequisites[i][0];
            int pcourse = prerequisites[i][1];
            graph.get(course).add(pcourse);
        }
        int[] visited = new int[numCourses];
        for(int i=0;i<numCourses;i++)
            if(DFS(i,graph,visited))
                return false;
        return true;
    }
 
    public boolean DFS(int curr,ArrayList<ArrayList<Integer>> graph,int[] visited)
    {
        //递归结束条件
        if(visited[curr]==1)//这个节点已经被访问
            return true;
        if(visited[curr]==2)//这个节点没有被访问
            return false;
         
        //业务逻辑处理
        visited[curr]=1;//表示正在访问
        for(int id:graph.get(curr))
            if(DFS(id,graph,visited))
                return true;
        visited[curr]=2;//表示已经访问
        return false;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值