一般我们认为,TopologicalSort是BFS中的一种。其实DFS也可以做拓扑排序,只是比较难理解。
拓扑排序适用于有向无环图(Directed Acyclic Graph)。
直观地理解:图中的节点,对于a given node,它依赖另外一个或多个点,看图中节点能否按依赖关系排序(prerequisite排在前面),并且遍历完全部节点。
题目 | 简介 |
---|---|
207. Course Schedule | 能否按依赖关系排序 |
210. Course Schedule II | 求依赖关系的整个路径 |
269. Alien Dictionary | 求依赖关系的整个路径 |
329. Longest Increasing Path in a Matrix | 求依赖关系的最长路径 |
444. Sequence Reconstruction | 检查是否是唯一的路径 |
1203. Sort Items by Groups Respecting Dependencies | 还没做:) |
207. Course Schedule
Input: numCourses = 2, prerequisites = [[1,0],[0,1]],问是否能把所有课都上了。Output: false
as usual, 先建构图。这个题我们已知numCourses,即节点个数已知且有限,于是可以用邻接矩阵来表示graph。
这个题除了graph,还要填写indegree,因为我们要找“改节点的所有prerequisite已经都clear了的节点”,即“indegree为零的点”,作为“当前可访问的点”,放进queue里(和BFS一样。注意“访问queue”是在出队的时候访问)。
剩下的工作就是BFS啦,由最开始的“indegree本来就是0的点”,逐渐扩散来访问,访问过当前点之后,把它的邻居indegree全都减一,因为这个点“学过了”,就清除了这个prerequisite,它的所有邻居就减少一个prerequisite。直到减到为0,就ready to visit啦,扔到队列里。
另外,这个是有向图,不需要visited数组来标记。而且访问完的点不用在graph里标记把这条边去掉,因为每个点只访问一次,边还是有序的,这个边不会再被访问了,所以无所谓。
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
//1)把边集合转化为邻接矩阵;2)填写indegree数组
int[][] graph = new int[numCourses][numCourses];
int[] indegree = new int[numCourses]; //"to"
for (int[] prerequisite : prerequisites) {
int from = prerequisite[0];
int to = prerequisite[1];
if (graph[from][to] == 0) {
indegree[to]++;
graph[from][to] = 1;
}
}
//先把indegree一开始就为零的点,放进queue里
int count = 0;
Queue<Integer> q = new LinkedList<>();
for (int i = 0; i < indegree.length; i++) {
if (indegree[i] == 0) {
q.offer(i);
}
}
//访问整个图
while (!q.isEmpty()) {
int from = q.poll();
count++;
//检查"from"的neighbors
for (int i = 0; i < numCourses; i++) {
if (graph[from][i] != 0) {
indegree[i]--;//更新邻居的indegree
if (indegree[i] == 0) {
//prerequisite cleared
q.offer(i);
}
}
}
}
return count == numCourses;
}
}
210. Course Schedule II
Input: 4, [[1,0],[2,0],[3,1],[3,2]],求某一个完整路径。
Output: [0,1,2,3] or [0,2,1,3]
210和209区别不大,就是增加了一个数组来记录路径即可。
class Solution {
public int[] findOrder(int numCourses, int[][] prerequisites) {
int[] order = new int[numCourses];//记录路径
int index = 0;
//1)把边集合转化为邻接矩阵;2)填写indegree数组
boolean[][] graph =