leetcode学习笔记22

207. 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?
部分转载于http://www.cnblogs.com/grandyang/p/4484571.html

这道课程清单的问题对于我们学生来说应该不陌生,因为我们在
选课的时候经常会遇到想选某一门课程,发现选它之前必须先上了哪些课程,这道题给了很多提示,第一条就告诉我们了这道题的本质就是在有向图中检测环。 LeetCode中关于图的题很少,有向图的仅此一道,还有一道关于无向图的题是 Clone Graph 无向图的复制。个人认为图这种数据结构相比于树啊,链表啊什么的要更为复杂一些,尤其是有向图,很麻烦。第二条提示是在讲如何来表示一个有向图,可以用边来表示,边是由两个端点组成的,用两个点来表示边。第三第四条提示揭示了此题有两种解法,DFS和BFS都可以解此题。我们先来看BFS的解法,我们定义二维数组graph来表示这个有向图,一位数组in来表示每个顶点的入度。我们开始先根据输入来建立这个有向图,并将入度数组也初始化好。然后我们定义一个queue变量,将所有入度为0的点放入队列中,然后开始遍历队列,从graph里遍历其连接的点,每到达一个新节点,将其入度减一,如果此时该点入度为0,则放入队列末尾。直到遍历完队列中所有的值,若此时还有节点的入度不为0,则说明环存在,返回false,反之则返回true。代码如下:

class Solution {
     public boolean canFinish(int numCourses, int[][] prerequisites) {
        ArrayList[] graph = new ArrayList[numCourses];
        int[] inDegree = new int[numCourses];
        for(int i=0;i<numCourses;i++) {
        	graph[i]=new ArrayList();
        }
        for(int i=0;i<prerequisites.length;i++) {
        	int pre=prerequisites[i][1];
        	int rear=prerequisites[i][0];
        	inDegree[rear]++;
        	graph[pre].add(rear);
        }
        Queue<Integer> queue=new LinkedList<Integer>();
        int count=0;
        for(int i=0;i<inDegree.length;i++) {
        	if(inDegree[i]==0) {
        		queue.offer(i);
        		count++;
        	}    		
        }
        while(!queue.isEmpty()) {
        	ArrayList<Integer> rem=graph[queue.poll()];
        	for(int i=0;i<rem.size();i++) {
        		int next=rem.get(i);
        		inDegree[next]--;
        		if(inDegree[next]==0) {
        			queue.offer(next);
            		count++;
        		}
        	}
        }
		return count==numCourses;
     }
}

下面我们来看DFS的解法,也需要建立有向图,还是用二维数组来建立,和BFS不同的是,我们像现在需要一个一维数组visit来记录访问状态,这里有三种状态,0表示还未访问过,1表示已经访问了,-1表示有冲突。大体思路是,先建立好有向图,然后从第一个门课开始,找其可构成哪门课,暂时将当前课程标记为已访问,然后对新得到的课程调用DFS递归,直到出现新的课程已经访问过了,则返回false,没有冲突的话返回true,然后把标记为已访问的课程改为未访问。代码如下:

class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
    	ArrayList[] graph = new ArrayList[numCourses];
    	int[] visit = new int[numCourses];
        for(int i=0;i<numCourses;i++) {
        	graph[i]=new ArrayList();
        }
        for(int i=0;i<prerequisites.length;i++) {
        	int pre=prerequisites[i][1];
        	int rear=prerequisites[i][0];
        	graph[pre].add(rear);
        }
        for(int i=0;i<graph.length;i++) {
        	if(!dfsHelper(graph,i,visit))
        		return false;
        }
		return true;
    }
    public boolean dfsHelper(ArrayList[] graph,int i,int[] visit) {
    	if(visit[i]==1)return true;
    	if(visit[i]==-1)return false;
    	visit[i]=-1;
    	for(int j=0;j<graph[i].size();j++) {
    		if(!dfsHelper(graph,(int)graph[i].get(j),visit))
        		return false;
    	}
    	visit[i]=1;
    	return true;
		  	
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_38941866/article/details/85010033