每日一题算法:2020.05.17 课程表II,,,,findOrder

2020.05.17 课程表IIfindOrder

题目:

在这里插入图片描述

函数格式:

class Solution {
    public int[] findOrder(int numCourses, int[][] prerequisites) {
    }
}

思路:

看完题干之后的感觉,好复杂,在稍微思考和看了提示和说明之后,想到了一个暴力的办法,不过需要先定义一个数据结构,为了不出意外,先对数据进行分析。

在这里插入图片描述
大致分为这么四种情况需要考虑

1,一个课有多个先修课程,就像是C

2,多个课程有同一个先修课程,就像A

3,一个课程没有先修课程,F,这种最简单

4, 一个课程和他的先修课程之间有一个循环,GH,这会导致无法完成,直接输出空数组。

然后,给我们的数据的格式是[ [][][ B,A] [E,B] [C,A] ]这样的格式,可以把它想成一个链,我们可以根据自己的需求,把它设置为高级课程指向低级课程或者低级课程指向高级课程。

思路拆解:

1,把给的二维数组装到一个容器中方便我们处理,容器是这种样子

HashMap<Integer, ArrayList<Integer>> courses=new HashMap<Integer, ArrayList<Integer>>();

Integer表示哪门课,ArrayList<Integer>表示他的直系先修课

比如数据[1,2]

通过HashMap找到1所在的位置,把2插入到List中,遍历完之前给的数组就能实现将数据全部插入

2,找到没有先修课的课程

很简单,再次遍历数组,只要在HashMap中找不到的,就是没有先修课的课程,找到没有先修课的直接装进result数组中。

3,此时计算数量,没有先修课的课程+有先修课的课程加起来应该是等于k的

4,先构建一个数组,里面是上一轮循环中不存在先修课的课程,第一次肯定是result数组,遍历存在的所有课程,查找他们里面的list中是否有上一轮被移除的课程,如果有,那么移除那个课程,并且判断list是否为空,如果list为空,则认为是该轮中被移除的,将其加入一个数组,就是那个上一轮被移除的数组。

5,

一轮循环结束时,先判断是否有课程被移除,如果没有,则认为是存在无法到达的课程,直接返回空数组。

将本轮被移除的课程加入到result中,并且判断result的长度是否等于课程总数,如果等于,返回result。

把上一轮移除的课程数组缓存这一轮移除的数组

6,到这里应该就已经结束了,完全不敢计算时间复杂度,太恐怖了,先试试能不能搞出来。

尴尬,感受一下

while (true){
    //遍历hashmap
    Iterator it = courses.entrySet().iterator();
    while (it.hasNext()){
        Map.Entry entry = (Map.Entry) it.next();
        ArrayList<Integer> course=(ArrayList<Integer>)entry.getValue();
        for (Integer integer : course) {
            for (int i=0;i<course1.size();i++){
                        //判断
                    }
        }
    }
}

这种循环四层的时间复杂度简直爆炸,如果工作上这么写肯定直接被开除了。能力有限,做不出来,先看一看教学视频吧,加强一下基础。

在看了视频之后,发现实际上的解法和这个差不多,所以我继续把他给补全了,但是遇到了问题

import org.junit.Test;

import java.lang.reflect.Array;
import java.util.*;

public class findOrder {
    @Test
    public void test(){
        int[][] course={{1,2},{1,3},{3,4},{3,5}};
        int [] courses=findOrder(5, course);
        for (int cours : courses) {
            System.out.println(cours);
        }

    }
    HashMap<Integer, ArrayList<Integer>> courses=new HashMap<Integer, ArrayList<Integer>>();
    public int[] findOrder(int numCourses, int[][] prerequisites) {


        int[] result=new int[numCourses];

        if (numCourses==1&&prerequisites.length==0)
        {
            for (int i=0;i<numCourses;i++){
                result[i]=numCourses-i-1;
            }
            return result;
        }
        int index=0;
        //上一轮移除的课程
        ArrayList<Integer> course1=new ArrayList<Integer>();
        //这一轮移除的课程
        ArrayList<Integer> course2=new ArrayList<Integer>();

        //遍历数组,把他们装进容器中
        for (int i=0;i<prerequisites.length;i++){
            if (courses.get(prerequisites[i][0])==null)
                courses.put(prerequisites[i][0], new ArrayList<Integer>());

            courses.get(prerequisites[i][0]).add(prerequisites[i][1]);
        }

        //如果没有一个课程没有子课程,直接返回空数组
        if (courses.size()==numCourses)
            return new int[0];

        //第一轮,装result课程,查看存在哪些没有子课程的课程
        for (int i=0;i<prerequisites.length;i++){
            if (courses.get(prerequisites[i][1])==null){
                //找到没出现过的课程,就是基础课程
                result[index]=prerequisites[i][1];
                index++;
            }

        }

        //将他们加入上一轮移除的课程中
        for(int i=0;i<index;i++)
        {
            course1.add(result[i]);
        }

        //进入无限循环,一层层剖析
        while (true){

            //遍历hashmap,遍历所有课程
            Iterator it = courses.entrySet().iterator();
            while (it.hasNext()){
                Map.Entry entry = (Map.Entry) it.next();
                ArrayList<Integer> course=(ArrayList<Integer>)entry.getValue();

                //遍历课程中的所有子课程
                for (Integer integer : course) {

                    //比较子课程和上一次遍历时移除的课程是否相等,
                    for (int i=0;i<course1.size();i++){
                        //如果相等,将其移除子课程
                        if(integer.equals(course1.get(i)))
                            course1.remove(i);
                    }

                    //判断子课程是否已经为空,如果为空,那么将其移除课程
                    if(course1.size()==0){
                        //将其加入本次移除的数组
                        course2.add((Integer)entry.getKey());
                        //将其加入result
                        result[index]=(Integer)entry.getKey();
                        index++;

                        //将其在hashmap中移除
                        courses.remove(entry.getKey());
                    }

                }
            }

            if (course2.size()==0){
                //如果本次没有课程被移除,说明已经结束了或者是出现了无法被移除的课程,即出现了闭环
                if(index==numCourses)
                    return result;
                else
                    return new int[0];
            }
            course1=course2;
            course2=new ArrayList<Integer>();
        }

    }

}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

是我的题目没能理解吗?

今天已经11点了,明天还要上班,这道题难度确实有点大,抄一抄答案明天加把劲给他补回来吧。

这是今天抄到的代码,不能死脑筋做不出就死犟着,如果花了两个小时还是没能做出来的话还是去看一看别人的做法学习一下比较好。

class Solution {
boolean hasCycle;
Deque<Integer> reversePost = new LinkedList<>();

public int[] findOrder(int V, int[][] A) {
    // 将边缘列表变为邻接列表
    List<Integer>[] G = (List<Integer>[])new ArrayList[V];
    for (int i = 0; i < V; i++) G[i] = new ArrayList<>();
    for (int[] a : A) G[a[1]].add(a[0]);

    int[] ans = new int[]{};

    findCycle(V, G);
    // 只有无环才能拓扑排序
    if (!hasCycle) {
        ans = new int[reversePost.size()];
        for (int i = 0; i < ans.length; i++) {
            ans[i] = reversePost.pop();
        }
    }
    return ans;
}

void findCycle(int V, List<Integer>[] G) {
    boolean[] seen = new boolean[V];
    boolean[] onstack = new boolean[V];
    for (int v = 0; v < V; v++) {
        if (!seen[v]) dfs(v, G, seen, onstack);
    }
}

void dfs(int v, List<Integer>[] G, boolean[] seen, boolean[] onstack) {
    if (hasCycle) return;
    seen[v] = true;
    onstack[v] = true;
    for (int w : G[v]) {
        if (!seen[w]) dfs(w, G, seen, onstack);
        else if (onstack[w]) {
            hasCycle = true;
            return;
        }
    }
    // 找环的同时进行记录拓扑排序
    reversePost.push(v);
    onstack[v] = false;
}

}

好希望有一天我也能自己写出这么棒的代码。

在这里插入图片描述

©️2020 CSDN 皮肤主题: 游动-白 设计师: 上身试试 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值