Solution 1
其实整体意思了解下来,就是希望我们找到可能存在的“逻辑环”。尽管之前我们已经学习了如何从链表中寻找环,但是在本题中仍然需要考虑一连多的情形,即从有向图中寻找可能的环。
这里就需要使用“拓扑排序”来寻找有向图中的环了。给定的输入数字即节点数量(一门课一个节点),而前提条件序列即为边,基于这一组内容完成一次拓扑排序。
本体需要着重关注存在环的情形。
- 时间复杂度: O ( N + M ) O(N + M) O(N+M),其中 N N N图的节点数量,即输入的课程数; M M M为边的数量,即输入的前提条件数量;拓扑排序中DFS完成所有节点的一次线性遍历,整体时间复杂度
- 空间复杂度: O ( N + M ) O(N+M) O(N+M),其中 N N N图的节点数量,即输入的课程数; M M M为边的数量,即输入的前提条件数量;搜索过程中对节点状态和图的整体存储占用
class Solution {
private:
vector<vector<int>> edges; // 输入图
vector<int> isVisited; // 搜索验证,0:未搜索,1:可达节点未全部遍历,2:可达节点全部遍历
vector<int> ans; // 拓扑排序结果
bool hasCycle = false; // 是否有环
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
this->edges = vector<vector<int>>(numCourses, vector<int>());
this->isVisited = vector<int>(numCourses);
for (auto item: prerequisites) {
this->edges[item[0]].push_back(item[1]);
}
this->topologicalSort(numCourses);
if (this->hasCycle) {
return false;
} else {
return true;
}
}
private:
void topologicalSort(int num) {
for (int vertex = 0; vertex < num; vertex++) {
if (isVisited[vertex] == 0) {
this->dfs(vertex);
}
if (this->hasCycle) {
return; // 发现环,提前终止
}
}
}
void dfs(int vertex) {
this->isVisited[vertex] = 1;
for (auto target: edges[vertex]) {
if (isVisited[target] == 0) {
this->dfs(target);
if (this->hasCycle) {
return; // 发现环,提前终止
}
} else if (this->isVisited[target] == 1) {
this->hasCycle = true;
return; // 发现环,提前终止
}
}
isVisited[vertex] = 2; // 完成全部可达节点遍历
ans.push_back(vertex);
}
};
Solution 2
Solution 1的Python实现
class Solution:
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
edges = collections.defaultdict(list)
is_visited = [0] * numCourses
ans = list()
has_cycle = False
def dfs(vertex: int) -> None:
nonlocal edges, is_visited, has_cycle
is_visited[vertex] = 1
for target in edges[vertex]:
if is_visited[target] == 0:
dfs(target)
if has_cycle: return
elif is_visited[target] == 1:
has_cycle = True
return
is_visited[vertex] = 2
ans.append(vertex)
def topological_sort(num_vertex: int) -> None:
nonlocal is_visited, has_cycle
for vertex in range(num_vertex):
if is_visited[vertex] == 0:
dfs(vertex)
if has_cycle: return
# ====================================
for item in prerequisites:
edges[item[0]].append(item[1])
topological_sort(numCourses)
if has_cycle:
return False
else:
return True