当前位置: 面试刷题>> 课程表(经典算法150题)
### 题目描述
假设你正在设计一个大学课程表系统,其中课程之间可能存在先修关系。例如,学习课程B之前必须先完成课程A。现在给你一个课程数量n和一个二维数组`prerequisites`,其中`prerequisites[i] = [ai, bi]`表示学习课程`bi`之前必须先完成课程`ai`。
你的任务是编写一个函数来判断是否存在一个合理的学习顺序,使得所有的课程都可以被学习。如果存在这样的顺序,则返回`true`;否则返回`false`。
**注意**:
1. 输入的课程数量n是一个正整数。
2. `prerequisites`中的每个课程对`[ai, bi]`都是唯一的,并且保证`bi`不会在`ai`的先修课程列表中。
### 示例
**示例 1**:
```
输入: n = 2, prerequisites = [[1,0]]
输出: true
解释: 存在一种学习顺序 [0,1],其中 0 是 1 的先修课程。
```
**示例 2**:
```
输入: n = 2, prerequisites = [[1,0],[0,1]]
输出: false
解释: 不存在一种学习顺序可以同时满足 0 是 1 的先修课程和 1 是 0 的先修课程。
```
### PHP 示例代码
```php
function canFinish($numCourses, $prerequisites) {
// 构建邻接表表示课程之间的先修关系
$graph = array_fill(0, $numCourses, []);
for ($i = 0; $i < count($prerequisites); $i++) {
$graph[$prerequisites[$i][1]][] = $prerequisites[$i][0];
}
// 初始化访问状态数组
$visited = array_fill(0, $numCourses, 0); // 0: 未访问, 1: 正在访问, 2: 已访问
// 遍历每个课程,检查是否存在环
for ($i = 0; $i < $numCourses; $i++) {
if (hasCycle($graph, $visited, $i)) {
return false;
}
}
return true;
}
function hasCycle($graph, &$visited, $course) {
if ($visited[$course] == 1) {
// 发现环
return true;
}
if ($visited[$course] == 2) {
// 课程已访问过,无环
return false;
}
$visited[$course] = 1; // 标记为正在访问
foreach ($graph[$course] as $preReq) {
if (hasCycle($graph, $visited, $preReq)) {
return true;
}
}
$visited[$course] = 2; // 标记为已访问
return false;
}
```
### Python 示例代码
```python
from collections import defaultdict
def canFinish(numCourses, prerequisites):
graph = defaultdict(list)
for pre, course in prerequisites:
graph[course].append(pre)
visited = [0] * numCourses # 0: 未访问, 1: 正在访问, 2: 已访问
def dfs(course):
if visited[course] == 1:
return True
if visited[course] == 2:
return False
visited[course] = 1
for pre in graph[course]:
if dfs(pre):
return True
visited[course] = 2
return False
for i in range(numCourses):
if dfs(i):
return False
return True
```
### JavaScript 示例代码
```javascript
function canFinish(numCourses, prerequisites) {
const graph = new Array(numCourses).fill(0).map(() => []);
for (const [pre, course] of prerequisites) {
graph[course].push(pre);
}
const visited = new Array(numCourses).fill(0); // 0: 未访问, 1: 正在访问, 2: 已访问
function dfs(course) {
if (visited[course] === 1) {
return true;
}
if (visited[course] === 2) {
return false;
}
visited[course] = 1;
for (const pre of graph[course]) {
if (dfs(pre)) {
return true;
}
}
visited[course] = 2;
return false;
}
for (let i = 0; i < numCourses; i++) {
if (dfs(i)) {
return false;
}
}
return true;
}
```
以上代码均实现了检查课程表中是否存在合理的学习顺序的逻辑,使用了深度优先搜索(DFS)来检测图中是否存在环,从而判断是否存在合理的学习顺序。