力扣热题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;
    }
}
相关推荐
罗西的思考1 小时前
AI Agent框架探秘:拆解 OpenHands(10)--- Runtime
人工智能·算法·机器学习
HXhlx4 小时前
CART决策树基本原理
算法·机器学习
Wect5 小时前
LeetCode 210. 课程表 II 题解:Kahn算法+DFS 双解法精讲
前端·算法·typescript
颜酱5 小时前
单调队列:滑动窗口极值问题的最优解(通用模板版)
javascript·后端·算法
Gorway12 小时前
解析残差网络 (ResNet)
算法
拖拉斯旋风12 小时前
LeetCode 经典算法题解析:优先队列与广度优先搜索的巧妙应用
算法
Wect12 小时前
LeetCode 207. 课程表:两种解法(BFS+DFS)详细解析
前端·算法·typescript
灵感__idea1 天前
Hello 算法:众里寻她千“百度”
前端·javascript·算法
Wect1 天前
LeetCode 130. 被围绕的区域:两种解法详解(BFS/DFS)
前端·算法·typescript
NAGNIP2 天前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试