615. Course Schedule-课程表(拓扑排序)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lighthear/article/details/79876678

Description

现在你总共有 n 门课需要选,记为 0 到 n - 1.
一些课程在修之前需要先修另外的一些课程,比如要学习课程 0 你需要先学习课程 1 ,表示为[0,1]
给定n门课以及他们的先决条件,判断是否可能完成所有课程?

样例

给定 n = 2,先决条件为 [[1,0]] 返回 true
给定 n = 2,先决条件为 [[1,0],[0,1]] 返回 false

Solution

算法思路:

已知node和edge构造存储有向图图的map,有了map之后,剩下的解法类似于127.topological sorting 那道题

具体解法:

1. 把输入的参数转换成map形式存储的图

2. 拓扑排序得到list of result

3. 判断list中的节点个数是否为numCourses。因为拓扑排序节点入度为0时才会存入result,所以如果存在环,那么有向图的拓扑排序节点个数就会小于图的节点个数。

public class Solution {
    /*
     * @param numCourses: a total of n courses
     * @param prerequisites: a list of prerequisite pairs
     * @return: true if can finish all courses or false
     */
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        // write your code here
        // 已知node和edge构造存储有向图图的map
        // 有了map之后,剩下的解法类似于topological sorting 那道题
        // 思路:1.把输入的参数转换成map形式存储的图
        // 2.拓扑排序得到list of result
        // 3.判断list中的节点个数是否为numCourses
        // 因为拓扑排序节点入度为0时才会存入result
        // 所以如果存在环,那么有向图的拓扑排序节点个数就会小于图的节点个数
        if (numCourses == 0 || prerequisites.length == 0) {
            return true;
        }
        
        //创建courseMap
        HashMap<Integer, List<Integer>> courseMap = creatCourseMap(numCourses, prerequisites);
        //统计各个节点的入度
        HashMap<Integer, Integer> indegreeMap = new HashMap<>();
        for (int i = 0; i < numCourses; i++) {
            for (Integer neighbor : courseMap.get(i)) {
                if (indegreeMap.containsKey(neighbor)) {
                    indegreeMap.put(neighbor, indegreeMap.get(neighbor) + 1);
                } else {
                    indegreeMap.put(neighbor, 1);
                }
            }
        }
        
        // 把所有入度为0的点,放到BFS专用的队列中
        Queue<Integer> queue = new LinkedList<>();
        // 初始化拓扑序列为空
        ArrayList<Integer> result = new ArrayList<>();
        for (int i = 0; i < numCourses; i++) {
            if (!indegreeMap.containsKey(i)) {
                queue.offer(i);
                result.add(i);
            }
        }
        
        // 每次从队列中拿出一个点放到拓扑序列里,并将该点指向的所有点的入度减1
        while (!queue.isEmpty()) {
            Integer course = queue.poll();
            for (Integer neighbor : courseMap.get(course)) {
                indegreeMap.put(neighbor, indegreeMap.get(neighbor) - 1);
                // 减去1之后入度变为0的点,也放入队列
                if (indegreeMap.get(neighbor) == 0) {
                    queue.offer(neighbor);
                    result.add(neighbor);
                }
            }
        }
        // 判断拓扑排序数与图的节点数是否相同
        return result.size() == numCourses;
    }
    
    //创建courseMap有向图,方向为先修课程指向当前课程pre -> sou
    private HashMap<Integer, List<Integer>> creatCourseMap(int numCourses, int[][] prerequisites) {
        HashMap<Integer, List<Integer>> map = new HashMap<>();
        for (int i = 0; i < numCourses; i++) {
            map.put(i, new ArrayList<>());
        }
        for (int i = 0; i < prerequisites.length; i++) {
            int sou = prerequisites[i][0];
            int pre = prerequisites[i][1];
            map.get(pre).add(sou);
        }
        return map;
    }
}

猜你喜欢

转载自blog.csdn.net/lighthear/article/details/79876678