题目链接,描述
https://www.lintcode.com/problem/1366
请你判断一个 n 个点,m 条边的有向图是否存在环。参数为两个int数组,start[i]到end[i]有一条有向边。
2 <= n <= 10^5
1 <= m <= 4*10^5
1 <= start[i], end[i] <= n
样例
样例1
输入: start = [1],end = [2]
输出: "False"
解释:
只有1->2一条边,不存在环
样例2
输入: start = [1,2,3],end = [2,3,1]
输出: "True"
解释:
存在1->2->3->1这个环
思路
使用拓扑排序,如果无法完成拓扑排序,则有向图存在环,时间复杂度O(n+m)
答案
public class Solution {
/**
* @param start: The start points set
* @param end: The end points set
* @return: Return if the graph is cyclic
*/
public boolean isCyclicGraph(int[] start, int[] end) {
//在拓扑排序中,我们需要创建一个队列,队列的初始元素为所有入度为 0 的课程。
// 对于有环图,一定会存在某一时间队列不存在入度为 0 的元素,但还未学习完全部课程的情况。
//主要考虑能不能完成拓扑排序,能完成就返回false,否则就返回true,说明有环
Map<Integer,Node> map = new HashMap<>();
int n= start.length;
for (int i = 0; i <n ; i++) {
int fromval = start[i];
int toval = end[i];
if(!map.containsKey(fromval))
map.put(fromval,new Node(fromval));
if(!map.containsKey(toval))
map.put(toval,new Node(toval));
Node nodef = map.get(fromval);
Node nodet = map.get(toval);
nodef.nexts.add(nodet);
nodet.in++;
}
Queue<Node> queue = new LinkedList<>();
for(int k: map.keySet()){
if(map.get(k).in ==0)
queue.add(map.get(k));
}
if(queue.isEmpty()) return true;
int step = 0;
while (!queue.isEmpty()){
int size= queue.size();
for (int i = 0; i <size ; i++) {
Node cur = queue.poll();
step++;
//System.out.print(cur.data+" ");
for (Node next : map.get(cur.data).nexts) {
if(--next.in ==0)
queue.add(next);
}
}
}
// System.out.println(n);
//System.out.println(" 长度:"+map.size()+" step="+step);
return step ==map.size()? false: true; //如果step==map.size() 说明能完成拓扑排序
}
static class Node {
int data;
int in;
List<Node> nexts;
public Node(int d) {
data = d;
in = 0;
nexts = new ArrayList<>();
}
}
}