力扣热题100道之207课程表

解法

题解中的广度优先算法

直接运用拓扑排序中的找入度为0的点的方法,就可以了。非常地清晰。

复制代码
class Solution {
   
    public boolean canFinish(int numCourses, int[][] prerequisites) {
       List<List<Integer>>edgs=new ArrayList();
       int []flag=new int[numCourses];
       for(int i=0;i<numCourses;i++){
            edgs.add(new ArrayList<Integer>());
       }
       for(int[]nums:prerequisites){
            edgs.get(nums[1]).add(nums[0]);
            flag[nums[0]]++;
       }
       Queue<Integer>queue=new LinkedList();
       for(int i=0;i<numCourses;i++){
            if(flag[i]==0){
                queue.offer(i);
            }
       }
       int visited=0;
       while(!queue.isEmpty()){
            visited++;
            int tmp=queue.poll();
            for(int v:edgs.get(tmp)){
                flag[v]--;
                if(flag[v]==0){
                    queue.offer(v);
                }
            }
       }
       return visited==numCourses;
    }
}
题解中的深度优先搜索

用图的数据结构来解题,将数组变成有向图。List<List<Integer>>外面是头,结束是尾。

三种状态,未访问(0),正在访问(1),访问过(2)

正在访问的时候发现访问到了正在访问的节点(有点绕,但想一下)就说明有环,访问到自己了。直接从栈里面弹出去(return)。如果已经知道存在环(flag=false)就直接弹出去(return),如果没有发现环,就正常地让节点进入到"访问过的状态(2)".

我在做这道题的时候遇到的一个问题就是,我开始没有搞明白题解中的return 是什么意思,dfs这个方法不需要返回什么东西,如果他走完了,可以将节点的状态变为访问过的状态,只有出现异常(发现了环)才会中间强制返回。

复制代码
class Solution {
    List<List<Integer>>edgs;
    boolean flag=true;
    int []visited;
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        int n = prerequisites.length;
        visited=new int[numCourses];
        edgs=new ArrayList<List<Integer>>();
        for(int i=0;i<numCourses;i++){
            edgs.add(new ArrayList<Integer>());
        }
        for(int []num:prerequisites){
            edgs.get(num[1]).add(num[0]);
        }
        for(int i=0;i<numCourses&&flag;i++){
            if(visited[i]==0){
                dfs(i);
            }
        }  
        return flag;
    }
    public void dfs(int i){
        visited[i]=1;
        for(int v:edgs.get(i)){
            if(visited[v]==0){
                dfs(v);
                if(!flag){
                    return;
                }
            }else if(visited[v]==1){
                flag=false;
                return;
            }
        }
        visited[i]=2;
    }
}
历史解法
报错超出时间限制的解法

这个方法时间复杂度O(n2)。每次都遍历整个数组,看能不能找到让序列连续下去,我想过用哈希表来做,但是哈希表一次只能存储一个键,比如(1,3)(1,2)只能留下一个。所以我还是直接让复杂度高一些,先做出来再说。

我又想了一下,先决条件,可以继承啊,所以采用Map<Integer,List<Integer>>这种数据结构,后面是前面的先决条件,这样就完美解决了这个问题,选择正确的数据结构的重要性,在这一刻体现出来了!!

在做的过程中我又发现,Map<Integer,Set<Integer>>map=new HashMap();这种数据结构好像更合适。用Map<Integer, Set<Integer>>存储数据,方便找。然后遍历集合,

复制代码
class Solution {
        public boolean canFinish(int numCourses, int[][] prerequisites) {
            int n = prerequisites.length;
            if (n > numCourses * (numCourses - 1) / 2) return false;
            Map<Integer, Set<Integer>> map = new HashMap();
            List<Integer> kk = new ArrayList();
            for (int i = 0; i < n; i++) {
                int k = prerequisites[i][0];
                int v = prerequisites[i][1];
                if (!map.containsKey(k)) {
                    kk.add(k);
                }
                map.computeIfAbsent(k, key -> new HashSet<>()).add(v);
            }
            for (int i = 0; i < kk.size(); i++) {
                boolean flag = true;
                Set<Integer> s = map.get(kk.get(i));
                while (flag) {
                    Set<Integer> toAdd = new HashSet();
                    for (int num : s) {
                        if (num == kk.get(i)) return false;
                        if (map.containsKey(num)) {
                            Set<Integer> s1 = map.get(num);
                            toAdd.addAll(s1);
                        }
                    }
                    if(s.containsAll(toAdd))flag=false;
                    s.addAll(toAdd);
                }

            }
            for (int i = 0; i < kk.size(); i++) {
                Set<Integer> s = map.get(kk.get(i));
                for (int num : s) {
                    if (num == kk.get(i)) return false;
                }
            }
            return true;
        }
    }
通过了52个例子的解法
复制代码
class Solution {
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        int n=prerequisites.length;
        if(n>numCourses*(numCourses-1)/2)return false;
        Map<Integer,Set<Integer>>map=new HashMap();
        List<Integer>kk=new ArrayList();
        for(int i=0;i<n;i++){
            int k=prerequisites[i][0];
            int v=prerequisites[i][1];
            if(!map.containsKey(k)){
                kk.add(k);
            }
            map.computeIfAbsent(k,key->new HashSet<>()).add(v);
        }
        for(int i=0;i<kk.size();i++){
            Set<Integer>s=map.get(kk.get(i));
            Set<Integer>toAdd=new HashSet();
            for(int num:s){
                if(num==kk.get(i))return false;
                if(map.containsKey(num)){
                    Set<Integer>s1=map.get(num);
                    toAdd.addAll(s1);
                }
            }
            s.addAll(toAdd);
        }
        for(int i=0;i<kk.size();i++){
            Set<Integer>s=map.get(kk.get(i));
            Set<Integer>toAdd=new HashSet();
            for(int num:s){
                if(num==kk.get(i))return false;
                if(map.containsKey(num)){
                    Set<Integer>s1=map.get(num);
                    toAdd.addAll(s1);
                }
            }
            s.addAll(toAdd);
        }
        for(int i=0;i<kk.size();i++){
            Set<Integer>s=map.get(kk.get(i));
            for(int num:s){
                if(num==kk.get(i))return false;
            }            
        }
        return true;
    }
}
相关推荐
学学学无无止境2 小时前
力扣-买卖股票的最佳时机
leetcode
这周也會开心2 小时前
Map的遍历方式
数据结构·算法
无敌最俊朗@2 小时前
C++ 值类别与对象模型面试题(12)
算法
代码不停3 小时前
Java模拟算法题目练习
java·开发语言·算法
前端小L3 小时前
图论专题(二):“关系”的焦点——一眼找出「星型图的中心节点」
数据结构·算法·深度优先·图论·宽度优先
资深web全栈开发3 小时前
贪心算法套路解析
算法·贪心算法·golang
~~李木子~~3 小时前
贪心算法实验2
算法·贪心算法
FanXing_zl3 小时前
快速掌握线性代数:核心概念与深度解析
线性代数·算法·机器学习
zzzsde4 小时前
【C++】红黑树:使用及实现
开发语言·c++·算法