拓扑排序问题。
class Solution { public: bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) { int Hash[10010];//每个节点的入度 vector<vector<int>> v(numCourses);//用于存储每个节点相邻的边 stack<int> s;//存放入度为0的节点 memset(Hash, 0, sizeof(Hash)); for(int i =0 ; i < prerequisites.size();i++){ pair<int, int>p = prerequisites[i]; int x = p.first; int y = p.second; cout<<"x = "<<x <<"y = "<<y<<endl; v[x].push_back(y); ++Hash[y]; } for(int i = 0; i < numCourses; i++){ if(Hash[i] == 0){ s.push(i); } } while (!s.empty()) { int cur = s.top();//找到入度为0的点 s.pop(); for(int i = 0; i < prerequisites.size(); i++){ pair<int, int>p = prerequisites[i]; int x = p.first; int y = p.second; if(cur == x){ for(int j = 0; j < v[cur].size(); j++){ --Hash[v[cur][j]];//删除以该点为起点的所有有向边 if(Hash[v[cur][j]] == 0) s.push(v[cur][j]); } break; } } } for(int i = 0; i < numCourses; i++){ if(Hash[i] != 0) return false; } return true; } };
补充一个python的实现:
1 class Solution: 2 #返回True表示有环,返回False表示无环 3 def dfs(self,visited,memo,dic,i): 4 if visited[i]: 5 return True 6 if memo[i] == 0: 7 return False 8 elif memo[i] == 1: 9 return True 10 for cs in dic[i]: 11 visited[i] = True 12 bl = self.dfs(visited,memo,dic,cs) 13 visited[i] = False 14 if bl: 15 #当前线路中出现了环,则标记当前课程为1,返回True 16 memo[i] = 1 17 return True 18 ##当前线路,已经找到最早的前置课程,没有出现"环",则标记为0,表示课程i是可以学习的 19 memo[i] = 0 20 return False#返回False表示无环,当前课程i,可以完成学习 21 22 def canFinish(self, numCourses: 'int', prerequisites: 'List[List[int]]') -> 'bool': 23 dic = {} 24 n = len(prerequisites) 25 for i in range(numCourses): 26 dic[i] = [] 27 for i in range(n): 28 cs = prerequisites[i][0]#当前课程 29 pre = prerequisites[i][1]#前置课程 30 dic[cs].append(pre) 31 visited = [False for _ in range(numCourses)] 32 memo = [-1 for _ in range(numCourses)] 33 for i in range(numCourses): 34 #只要出现过一个有环的线路,则不能符合题目"所有课程都完成"的目标 35 if self.dfs(visited,memo,dic,i): 36 return False 37 return True
算法思路:深度优先遍历,判断图中是否有环。
使用两个标记数组:
visited=True表示当前“线路”上的节点已经被锁定,如果在线路遍历的过程中遇到已经被锁定的节点,那说明遇到了环。
memo表示备忘录(缓存),默认状态为-1,标记为0表示本节点不存在环,标记为1表示本节点有环,使用备忘录可加速得到查询结果。