LeetCode 第207题:课程表

1、前言

题目描述

2、思路

使用拓扑排序的方法,拓扑排序其实是使用的 BFS 算法,简而言之使用 BFS 算法解题。算法流程如下:

  • 1、统计课程安排图中每个节点的入度,生成入度表 indegrees
  • 2、借助一个队列 queue,将所有入度为0的节点入队
  • 3、当 queue 非空时,依次将队首节点出队,在课程安排图中删除此节点 pre:
    1) 并不是真正从邻接表中删除此节点 pre,而是将此节点对应所有邻接节点 cur 的入度 -1,即 indegrees[cur] -= 1。
    2) 当入度减1后邻接节点 cur 的入度为0,说明 cur 所有的前驱节点已经被“删除”,此时将 cur 入队
  • 4、在每次 pre 出队时,执行 numCourses--
    1) 若整个课程安排图是有向无环图,则所有节点一定都入队并出队过,即完成拓扑排序。换个角度,若课程安排图中存在环,一定有节点的入度始终不为0.
    2) 所以,拓扑排序出队次数等于课程个数,返回 numCourses == 0 判断课程是否被成功安排。

或者使用图遍历的方法。

3、代码

拓扑排序:

class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        int[] indegrees = new int[numCourses];

        // 每个点对应的边
        Map> adjacency = new HashMap<>();
        Queue queue = new LinkedList<>();
        for(int i = 0; i < numCourses; i++){
            adjacency.put(i, new ArrayList<>());
        }

        // 二维数组,每一行有两列,即两个值,代表 cp[1] -> cp[0] 的方向
        for(int[] cp : prerequisites){
            indegrees[cp[0]]++;
            adjacency.get(cp[1]).add(cp[0]);
        }

        // 将入度为0的顶点加入队列
        for(int i = 0; i < numCourses; i++){
            if(indegrees[i] == 0){
                queue.offer(i);
            }
        }

        // BFS
        while(!queue.isEmpty()){
            int pre = queue.poll();
            numCourses--;
            for(int cur : adjacency.get(pre)){
                if(--indegrees[cur] == 0){
                    queue.offer(cur);
                }
            }
        }

        return numCourses == 0;
    }
}

图遍历:

class Solution {

    class Graph{
        int val;
        List neighbors = new ArrayList<>();

        public Graph(int val){
            this.val = val;
        }
    }

    
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        if(prerequisites.length == 0){
            return true;
        }
        Map map = new HashMap<>();
        int m = prerequisites.length;

        for(int i = 0; i < m; i++){
            int pre = prerequisites[i][1], next = prerequisites[i][0];
            Graph graphPre = map.getOrDefault(pre, new Graph(pre));
            Graph graphNext = map.getOrDefault(next, new Graph(next));
            graphPre.neighbors.add(graphNext);
            map.putIfAbsent(pre, graphPre);
            map.putIfAbsent(next, graphNext);
        }

        int[] visited = new int[numCourses];
        for (Integer pre : map.keySet()) {
            if(cycle(map.get(pre), visited)){
                return false;
            }
        }
        return true;
    }

    private boolean cycle(Graph graph, int[] visited){
        if(visited[graph.val] == 1){
            return true;
        }

        if(visited[graph.val] == 2){
            return false;
        }
        visited[graph.val] = 1;
        for(Graph no : graph.neighbors){
            if(cycle(no, visited)){
                return true;
            }
        }

        visited[graph.val] = 2;
        return false;
    }
}

你可能感兴趣的:(LeetCode 第207题:课程表)