LeetCode刷题Medium篇Course Schedule

题目

There are a total of n courses you have to take, labeled from 0 to n-1.

Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]

Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?

Example 1:

Input: 2, [[1,0]] 
Output: true
Explanation: There are a total of 2 courses to take. 
             To take course 1 you should have finished course 0. So it is possible.

Example 2:

Input: 2, [[1,0],[0,1]]
Output: false
Explanation: There are a total of 2 courses to take. 
             To take course 1 you should have finished course 0, and to take course 0 you should
             also have finished course 1. So it is impossible.

Note:

  1. The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented.
  2. You may assume that there are no duplicate edges in the input prerequisites

十分钟尝试

知道这是个有向图,题目其实要求的就是判断这个有向图是否有环。如果有环,就是循环以来,题目无解。下面我们来学习一下如何判断一个有向图是否有环。有三种方法

1. DFS

2. BFS

3 Kahn 算法

有向图BFS算法

BFS的结果是: 5 2 3 4 0 1 或者 5 2 3 4 1 0最后两位取决于二维数组入队列的顺序

看了思路之后,自己代码实现一下。

1. 计算所有节点的入度,存入indegree数组,节点值就是数组索引

2. 遍历indegree数组,入度为0的入队列

3 遍历队列,直到为空,取出队列元素,遍历二维数组,如果“出发”元素为当前节点值,那么所有“子节点”入度减去1(此操作相当于把当前处理的入度为0的节点拿掉)

4 如果子节点入度变为0,入队列

5 最后如果所有节点都能入度为0,则没有环,否则有环

代码有个错误点,判断入度为0入队列的时候,add进去的是j,索引,不是indegree[j]。

class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        //BFS
        if(numCourses<0){
            return false;
        }
        //计算所有节点的入度,第二列数据
        int[] indegree=new int[numCourses];
        for(int i=0;i<prerequisites.length;i++){
            indegree[prerequisites[i][1]]++;
        }
        //入度为0的入队列
        Deque<Integer> queue=new LinkedList();
        for(int j=0;j<indegree.length;j++){
            if(indegree[j]==0){
                //此处入j不是indegree[j],因为索引就是值
                 queue.offer(j);
            }
        }
        //循环取出队列元素,开始遍历
        while(!queue.isEmpty()){
             int curr=queue.poll();
             for(int i=0;i<prerequisites.length;i++){
                 if(curr==prerequisites[i][0]){
                     indegree[prerequisites[i][1]]--;
                     if(indegree[prerequisites[i][1]]==0){
                         queue.add(prerequisites[i][1]);
                     }
                 }
             }   
        }
        //判断是否存在入度不为0的
        for(int i=0;i<indegree.length;i++){
            if(indegree[i]!=0){
                return false;
            }
        }
        return true;
    }
}

有向图的DFS算法

深度优先,很显然我们需要找到最底层的节点,也就是没有出度的节点。

1. 找到出度为0度节点,存入集合S

2 遍历集合S,如果当前节点m未访问,标记为访问

3  所有指向m的节点,递归访问。

4  当前节点m加入结果集

DFS的结果是: 1 3 2 5 0 4

DFS的代码暂时没有彻底理解,先记录一下:

class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
       //DFS
        ArrayList[]  graph=new ArrayList[numCourses];
        boolean[] visited=new boolean[numCourses];
        for(int i=0;i<graph.length;i++){
            graph[i]=new ArrayList<Integer>();
        }
        
        for(int i=0;i<prerequisites.length;i++){
           // graph[i]=prerequisites[i][1];注意这行
            graph[prerequisites[i][1]].add(prerequisites[i][0]);
        }
        for(int i=0;i<numCourses;i++){
            if(!dfs(graph,visited,i)){
                return false;
            }
        }
        return true;
    }
    
    private boolean dfs(ArrayList[] graph,boolean[] visited,int course){
        if(visited[course]){
            return false;
        }
        else{
            visited[course]=true;
        }
        for(int i=0;i<graph[course].size();i++){
            if(!dfs(graph,visited,(Integer)graph[course].get(i))){
                return false;
            }
        }
        visited[course]=false;
        return true;
    }
}

猜你喜欢

转载自blog.csdn.net/hanruikai/article/details/85629425