判断有向无环图(DAG)
其实,这篇博文是前面两篇的应用,并不算是一个基础操作。看起来可能会有点重复,但是作为巩固复习一下也不错。我感觉最近可能代码贴太多了,我有时间的时候,多加入一些注解吧。可能会适当加一些图。
方法一 广度优先遍历 + 入度统计
首先,找到入度为0的元素,这个元素肯定是“根”元素。接着,去掉这个元素,并相应减少邻接节点的入度,将新的入度为0的元素加入队列中。这样一系列操作之后,如果存在环,肯定有元素的入度始终不为0,从来没有被访问过,从而可以判断是否存在环。
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
class Solution {
private List<Integer>[] adjs;
private int[] indegrees;
private boolean[] visited;
public boolean containsLoop(int n, int[][] edges) {
adjs = new List[n];
indegrees = new int[n];
visited = new boolean[n];
for(int i = 0; i < n; i++) {
adjs[i] = new LinkedList<>();
}
// 入度和邻接矩阵初始化
for(int i = 0 ; i<edges.length;i++) {
int[] edge = edges[i];
int from = edge[0];
int to = edge[1];
adjs[from].add(to);
indegrees[to] += 1;
}
// 广度优先遍历
Queue<Integer> q = new LinkedList<>();
for (int i = 0 ; i < n; i++) {
if (indegrees[i] == 0) {
q.add(i);
}
}
while(!q.isEmpty()) {
int i = q.poll();//先访问入度为0的点,并去掉它
visited[i] = true;
for(int adj: adjs[i]) {
indegrees[adj] -=1;//更新入度
if (indegrees[adj] == 0) q.add(adj); // 添加入度为0的点
}
}
for (int i = 0 ; i < n;i++) {
if (!visited[i]) return true;
}
return false;
}
}
方法二 深度优先遍历
这里采用了涂色递归的方法进行深度优先遍历。灰色的元素处于同一条递归调用上,是同一条线,如果访问到了灰色元素(正常是黑色或者白色),说明存在环。
import java.util.LinkedList;
import java.util.List;
class Solution {
private List<Integer>[] adjs;
private Color[] colors;
public boolean containsLoop(int n, int[][] edges) {
adjs = new List[n];
colors = new Color[n];
for(int i = 0; i < n; i++) {
adjs[i] = new LinkedList<>();
colors[i] = Color.WHITE;
}
// 邻接矩阵和颜色初始化
for(int i = 0 ; i<edges.length;i++) {
int[] edge = edges[i];
int from = edge[0];
int to = edge[1];
adjs[from].add(to);
}
// 通过深度优先遍历判断环是否存在
for (int i = 0; i < n;i++) {
if (colors[i] == Color.WHITE) {
if(dfsVisit(i)) return true;
}
}
return false;
}
// contains loop return true;
// else return false;
private boolean dfsVisit(int i) {
colors[i] = Color.GRAY;
for (Integer adj: adjs[i]) {
if (colors[adj] == Color.GRAY) return true; // 在同一条递归调用中,访问到自己的先祖。
if (colors[adj] == Color.WHITE) {//没有访问的元素是白色的
if (dfsVisit(adj)) return true;
else continue;
}
}
colors[i] = Color.BLACK;
return false;
}
private enum Color {
WHITE, GRAY, BLACK
}
}