中级农民
- 积分
- 116
- 大米
- 颗
- 鳄梨
- 个
- 水井
- 尺
- 蓝莓
- 颗
- 萝卜
- 根
- 小米
- 粒
- 学分
- 个
- 注册时间
- 2018-4-21
- 最后登录
- 1970-1-1
|
207. Course Schedule 210. Course Schedule II
拓扑排序,拓扑排序是非常重要的图论的写法,之前就没有太理解,现在更加深刻了一些。
dfs写法可能对我比较好理解。
我认为拓扑排序主要难度在于编程技巧……
每一个节点一共有三个状态,状态1,未读取,状态2,正在读取,状态3, 已经读取。
默认都是未读取的状态。
我们从入度为0的节点开始,
先把它标记为状态2, 然后遍历它的邻居。
若是它没有邻居,就把它标记为已读取。再继续找下一个入读为零的节点重新开始。。
若是它有邻居,就递归进去。
当所有邻居都遍历完成,我们就把当前节点标记未状态3已读取。
递归的返回条件有两个,一个是遇到状态3,那么我们直接返回。另一个是遇到状态2, 此时说明有环。
这就是总体的逻辑,但是问题在于如何编程。
我看了看最简单的写法是定义一个int[] visit = new int[numCourses];
visit[i] = 0 状态 1 未读取
visit[i] = -1 状态2 在读取
visit[i] = 1 状态3 已读取
每次进入递归先判断visit的值,然后根据值返回或继续。若是visit[i] = 0,我们就先让它为 -1,再遍历邻居,再设置为1。
所以代码就是- class Solution {
- List<Integer> rs = new ArrayList<>();
- public int[] findOrder(int numCourses, int[][] prerequisites) {
- if( prerequisites.length == 0){
- int[] res = new int[numCourses];
- for(int i = 0; i < numCourses; i++) {
- res[i] = i;
- }
- return res;
- }
- Map<Integer, List<Integer>> map = new HashMap<>();
-
- for(int[] a : prerequisites) {
- List<Integer> l = map.getOrDefault(a[0], new ArrayList<>());
- l.add(a[1]);
- map.put(a[0], l);
- }
- int[] visit = new int[numCourses];
- for(int i = 0; i < numCourses; i++) {
- if(!helper(i, visit, map)) return new int[0];
- }
-
- int[] res = new int[numCourses];
- for(int i = 0; i < rs.size(); i++) {
- res[i] = rs.get(i);
- }
- return res;
- }
-
- private boolean helper(int node, int[] visit, Map<Integer, List<Integer>> map) {
- if(visit[node] > 0) {
- return true;
- }
- if(visit[node] < 0){
- return false;
- }
-
- visit[node] = -1;
-
- if(map.containsKey(node)) {
- List<Integer> nei = map.get(node);
- for(int next : nei) {
- if(!helper(next, visit, map)) return false;
- }
- }
-
- visit[node] = 1;
- rs.add(node);
- return true;
- }
- }
复制代码 |
|