2017.9.11
刚开始想的是,建立parent 和 children的树,如果有既是children 又是parent的节点,那么就返回false。
这种方法没有超时,但是超出了空间限制。
后来学习到采用拓扑排序的办法。关于图的思路写在了代码的注释里边。
在细节的处理方面有不同的方法。一个是最后的最后统一判断是不是还有入度不为0的点。这样会超时。
后来是在找入度为0的点的时候就进行判断,然而还是会超时。
后来又优化了许多地方。但是总是超时,我也没办法,实在是不知道为啥了。就先这样吧。
再再后来,我知道了,是找到一个入度为0得点之后,这个点的入度应该改变为-1,不然会重复选取。
终于找到了自己错误的地方,好开心。
最初的超时代码
public static class myCourse{
HashSet<Integer> parent;
HashSet<Integer> children;
public myCourse(){
parent = new HashSet<Integer>();
children = new HashSet<Integer>();
}
}
public static boolean canFinish1(int numCourses, int[][] prerequisites) {
// Write your code here
myCourse []arr = new myCourse[numCourses];
for(int []x : prerequisites){
if(arr[x[0]] == null){
arr[x[0]] = new myCourse();
}
if(!arr[x[0]].children.contains(arr[x[1]])){
arr[x[0]].children.add(x[1]);
}
if(arr[x[1]] == null){
arr[x[1]] = new myCourse();
}
if(!arr[x[1]].parent.contains(arr[x[0]])){
arr[x[1]].parent.add(x[0]);
}
for(int tmp : arr[x[1]].children){
if(tmp == x[0]){
return false;
}
if(!arr[x[0]].children.contains(tmp)){
arr[x[0]].children.add(tmp);
}
}
for(int tmp : arr[x[0]].parent){
if(tmp == x[1]){
return false;
}
if(!arr[x[1]].parent.contains(tmp)){
arr[x[1]].parent.add(tmp);
}
}
}
return true;
}
后来的超时代码,就是最后统一检查入度的方法。
public static boolean canFinish2(int numCourses, int[][] prerequisites){
// 首先是要构建图。
ArrayList<HashSet<Integer>> list = new ArrayList<HashSet<Integer>>();
// 先建立头结点。
for(int i = 0; i < numCourses; i++){
list.add(new HashSet<Integer>());
}
//建立所有的后序链表。 // inDegree计算所有的节点的入度。
int []inDegree = new int[numCourses];
for(int []x : prerequisites){
if(!list.get(x[0]).contains(x[1])){
list.get(x[0]).add(x[1]);
inDegree[x[1]] ++;
}
}
//找到一个入度为0的节点,开始遍历。
for(int j = 0; j < numCourses; j++){
int i = 0;
for(i = 0; i < inDegree.length;i++){
//在这里找到了一个入度为0的点。
if(inDegree[i] == 0 && !list.get(i).isEmpty()){
Iterator ite = list.get(i).iterator();
while(ite.hasNext()){
int tmp = (int)ite.next();
inDegree[tmp]--;
ite.remove();
}
break;
}
}
}
for(int i = 0; i< inDegree.length;i++){
if(inDegree[i] != 0){
return false;
}
}
return true;
}
最后最后,把能简化的都简化了,然而还是超时的代码。
后来稍稍修改一下。就AC了。
public static boolean canFinish(int numCourses, int[][] prerequisites){ // 首先是要构建图。 ArrayList<HashSet<Integer>> list = new ArrayList<HashSet<Integer>>(); // 先建立头结点。 for(int i = 0; i < numCourses; i++){ list.add(new HashSet<Integer>()); } //建立所有的后序链表。 for(int []x : prerequisites){ list.get(x[0]).add(x[1]); } // inDegree计算所有的节点的入度。 int []inDegree = new int[numCourses]; for(HashSet set : list){ Iterator ite = set.iterator(); while(ite.hasNext()){ inDegree[(int)ite.next()]++; } } //找到一个入度为0的节点,开始遍历。 for(int j = 0; j < numCourses; j++){ int i = 0; for(i = 0; i< numCourses;i++){ //在这里找到了一个入度为0的点。 if(inDegree[i] == 0){ break; } } if(i == numCourses){ return false; } //这里这里就是在这里啊,这个我忽视了啊啊啊啊。
Iterator ite = list.get(i).iterator();while(ite.hasNext()){inDegree[(int)ite.next()]--;}}return true;}inDegree[i] = -1;