Day82 课程表

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

在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi 。

例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。
请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false

https://leetcode-cn.com/problems/course-schedule/

示例1:

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

示例2:

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

提示:

1 <= numCourses <= 105
0 <= prerequisites.length <= 5000
prerequisites[i].length == 2
0 <= ai, bi < numCourses
prerequisites[i] 中的所有课程对 互不相同

Java解法

思路:

  • 初步思考,这种有关联的数据类似于链表结构,如果链表有环,那么这个数据将互相死锁无法学习

    • 双向链表:前节点为前置学习课程,后节点为后续学习课程,无前节点可作为学习课程起点
    • 学习数量:可以通过起点遍历记数返回
  • 因为没用提供数据结构供解题,这里先采用hashmap来记录对应关系

    public static boolean canFinish(int numCourses, int[][] prerequisites) {
        if (prerequisites == null||prerequisites.length==0) {
            return true;
        }
        HashMap<Integer, List<Integer>> map = new HashMap<>();//记录学 a课需要先学的b课
        HashMap<Integer, List<Integer>> map2 = new HashMap<>();//记录 已学 a课,可以学的b课
        for (int[] prerequisite : prerequisites) {
            List<Integer> list = map.getOrDefault(prerequisite[0], new ArrayList<>());
            list.add(prerequisite[1]);
            List<Integer> list1 = map.getOrDefault(prerequisite[1], new ArrayList<>());
            map.put(prerequisite[0], list);
            map.put(prerequisite[1], list1);
    
            List<Integer> integers = map2.getOrDefault(prerequisite[1], new ArrayList<>());
            integers.add(prerequisite[0]);
            map2.put(prerequisite[1],integers);
        }
        List<Integer> start = new ArrayList<>();
        for (Map.Entry<Integer, List<Integer>> entry : map.entrySet()) {
            if (entry.getValue()==null||entry.getValue().size()==0) {
                start.add(entry.getKey());
            }
        }
        int count = numCourses;
        for (Integer integer : start) {
            count--;
            int unLearn = learnFinish(map2, integer, count);
            if (unLearn<=0) {
                return true;
            }
            count = unLearn;
        }
        return count<=0;
    }
    public static int learnFinish(HashMap<Integer, List<Integer>> map,int index,int count){
        List<Integer> integers = map.getOrDefault(index,new ArrayList<>());
        count-=integers.size();
        for (Integer i : integers) {
            count -= learnFinish(map, i, count);
        }
        return count;
    }
    
  • 不知道是理解错误,这里的课程数无关结果,这里要求的是课程是不是能学完,脑壳大

  • 参考官方解:拓扑排序+深度优先搜索+回溯

    • 使用数组记录搜索状态,使用栈记录回溯完成遍历节点
package sj.shimmer.algorithm.m4_2021;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by SJ on 2021/4/19.
 */

class D82 {
    public static void main(String[] args) {
        System.out.println(canFinish(2,new int[][]{
                {1,0},
                {2,1},
        }));
        System.out.println(canFinish(20,new int[][]{
                {0,10},
                {3,18},
                {5,5},
                {6,11},
                {11,14},
                {13,1},
                {15,1},
                {17,4},
        }));
        System.out.println(canFinish(1,new int[][]{}));
    }

    static List<List<Integer>> edges;
    static int[] visited;//0 未搜索,1 搜索中(有环,无法完成),2 完成
    static boolean valid = true;

    public static boolean canFinish(int numCourses, int[][] prerequisites) {
        edges = new ArrayList<List<Integer>>();
        for (int i = 0; i < numCourses; ++i) {
            edges.add(new ArrayList<Integer>());
        }
        visited = new int[numCourses];
        for (int[] info : prerequisites) {
            edges.get(info[1]).add(info[0]);//记录学完 可以学的课,
        }
        for (int i = 0; i < numCourses && valid; ++i) {
            if (visited[i] == 0) {
                dfs(i);//开始深度搜索
            }
        }
        return valid;
    }

    public static void dfs(int u) {
        visited[u] = 1;
        for (int v: edges.get(u)) {
            if (visited[v] == 0) {
                dfs(v);
                if (!valid) {
                    return;
                }
            } else if (visited[v] == 1) {
                valid = false;
                return;
            }
        }
        visited[u] = 2;
    }
}

官方解

https://leetcode-cn.com/problems/course-schedule/submissions/

  1. 深度优先搜索

    如上

    • 时间复杂度: O(n+m)
  • 空间复杂度: O(n+m)
  1. 广度优先搜索:上方逆序操作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值