1. 题目
读题
考查点
2. 解法
思路
这个问题可以用图论的方法来解决,具体思路如下:
将课程和先修课程看作有向图的节点和边,如果要学习课程ai,则必须先学习课程bi,表示为bi->ai。
判断图中是否存在环,如果存在环,则说明有些课程无法完成,返回false;如果不存在环,则说明所有课程都可以完成,返回true。
判断图中是否存在环的方法有多种,例如深度优先搜索(DFS),广度优先搜索(BFS),拓扑排序(Topological Sort)等。
以下是用Java实现的一种基于DFS的解法,代码参考了Leetcode上的一个解答。
代码逻辑
这个代码的具体逻辑。😊
- 首先,我们需要创建一个邻接表来表示图,邻接表是一个列表,每个元素是一个列表,表示一个节点的邻接节点。例如,如果有一条边从节点0指向节点1,那么在邻接表中,第0个元素的列表中就会包含1。
- 然后,我们需要创建一个访问状态数组来记录每个节点的访问状态,初始值都为0,表示未访问。当我们开始访问一个节点时,我们将其状态改为1,表示正在访问;当我们结束访问一个节点时,我们将其状态改为2,表示已访问。
- 接下来,我们需要遍历每个节点,对每个节点进行深度优先搜索。深度优先搜索的思想是从一个节点出发,沿着一条路径不断向前探索,直到无法继续或者发现环为止,然后回溯到上一个节点,再沿着另一条路径继续探索,直到遍历完所有的节点为止。
- 在深度优先搜索的过程中,我们需要判断是否存在环。如果我们发现当前正在访问的节点已经被标记为正在访问,那么说明存在环;如果我们发现当前正在访问的节点已经被标记为已访问,那么说明不存在环;如果我们发现当前正在访问的节点还未被访问过,那么我们就将其标记为正在访问,并且递归地对其邻接节点进行深度优先搜索。
- 最后,如果在深度优先搜索的过程中没有发现环,那么就返回true,表示所有课程都可以完成;如果发现了环,那么就返回false,表示有些课程无法完成。
具体实现
class Solution { public boolean canFinish(int numCourses, int[][] prerequisites) { // 创建邻接表表示图 List<List<Integer>> adjList = new ArrayList<>(); for (int i = 0; i < numCourses; i++) { adjList.add(new ArrayList<>()); } for (int[] pre : prerequisites) { adjList.get(pre[1]).add(pre[0]); } // 创建访问状态数组,0表示未访问,1表示正在访问,2表示已访问 int[] visited = new int[numCourses]; // 遍历每个节点,进行深度优先搜索 for (int i = 0; i < numCourses; i++) { if (dfs(i, adjList, visited)) { return false; // 如果发现环,返回false } } return true; // 如果没有发现环,返回true } // 深度优先搜索函数,返回是否存在环 private boolean dfs(int cur, List<List<Integer>> adjList, int[] visited) { if (visited[cur] == 1) { return true; // 如果当前节点正在访问,说明存在环 } if (visited[cur] == 2) { return false; // 如果当前节点已访问,说明不存在环 } visited[cur] = 1; // 将当前节点标记为正在访问 for (int next : adjList.get(cur)) { // 遍历当前节点的邻接节点 if (dfs(next, adjList, visited)) { return true; // 如果邻接节点存在环,返回true } } visited[cur] = 2; // 将当前节点标记为已访问 return false; // 返回false表示不存在环 } }