Leetcode day3:课程表(有向图找圈)

先吐槽一下自己。。。这两天犯懒了,就忘记更博客了,之前上课也是,笔记一直拖到了最后一天才上传。。。还不是很习惯每天打开博客看一看,写点东西,但是还是决定养成分享和学习的习惯。

原题:

你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-1 。

在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]

给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习?

示例 1:

输入: 2, [[1,0]]
输出: true
解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。
示例 2:

输入: 2, [[1,0],[0,1]]
输出: false
解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成​课程 0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。

提示:

1.输入的先决条件是由 边缘列表 表示的图形,而不是 邻接矩阵 。详情请参见图的表示法。
2.你可以假定输入的先决条件中没有重复的边。
3.1 <= numCourses <= 10^5

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/course-schedule

思路和代码:

思路:

很简单的转化成一个在有向图里找有没有圈的问题。然后用DST或者是BST遍历整个图去判断有没有圈即可。
主要流程:
建立栈s,大小为numCourse的boolean数组searched(来记录走过的点),counter:记录已经走过的路径的长度,new和next用来存储当前的节点和下一个要找的节点(因为对边缘列表不是很熟悉,直接采用了遍历找头结点的方法,导致复杂度很高。)prenew用来在找到错误结点的时候回档。
向栈中压入-1
->找到任意一个节点->找到一条边->检查边的下一个节点是否已经遍历
.->已经遍历->利用edge和prenew回档,counter- -。
.->未遍历->将new设为该点,并入栈,设标志位为true。
.->该节点下已经没有出边->next=s.pop;counter- -;
->next==-1时(说明栈已空)结束上述过程的循环。

->若此时仍有未遍历的点,将next设为该点,并重新将-1入栈,重复加粗的过程直到所有的点都已经遍历。
最后在赞一下leetcode的测试数据,那是真的全面。。无数个被我忽略的情况都考虑进去了。
再补充一点优化思路:可以先遍历一遍边表,把入度为0的点先剔除,然后把从它出去的边也去掉,然后再找有没有可以剔除的点和边。简化完之后在开始深度或者广度优先搜索就可以了。

代码:
import java.util.Stack;

public class Solution {
	 public static boolean canFinish(int numCourses, int[][] prerequisites) {
		 	Stack<Integer> s = new Stack<>();
		 	int now = -1,next = -1,prenow = -1;
		 	int counter = 0;
		 	int i = 0;
		 	int j = 0;
		 	boolean[] searched = new boolean[numCourses];
		 	if(prerequisites.length==0||prerequisites.length==1)return true;
		 	now = prerequisites[0][0];
		 	next = now;
		 	
		 	while(true) {
		 		s.add(-1);
		 		//s.add(now);
		 		//searched[now]=true;
			 	while(next!=-1) {
			 		for(i=0;i<prerequisites.length;i++) {
			 			if(prerequisites[i][0] == next) {
			 				next = prerequisites[i][1];
			 				prenow = now;
			 				now = next;
			 				counter++;
			 				if(next!=-1&&searched[next]) {
			 					if(counter>1&&s.contains(next))return false;
			 					next = prerequisites[i][0];
			 					now = prenow;
			 					counter--;
			 					continue;
			 				}
			 				else break;
			 			}
			 			
			 		}
			 		if(i==prerequisites.length) {
			 			searched[next] = true;
			 			next = s.pop();
			 			counter--;
			 		}
			 		else if(next!=-1&&!searched[next]){
			 			s.add(now);
			 			searched[now] = true;
			 			now = next;
		 			}
//		 			else if(!s.empty()){	
//		 				next = s.pop();
//		 				counter--;
//		 			}
			 	}
			 	
			 	
			 	
			 	for(j=0;j < searched.length;j++)
			 	{
			 		if(!searched[j]) {
			 			now = j;
			 			next = now;
			 			counter = 0;
			 			break;
			 		}
			 	}
			 	if(j==searched.length) {
			 		return true;
			 	}
			 	
			 	
		 	}
		 
		 	
	 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值