【每日一题Day324】LC1462课程表 IV | BFS 拓扑排序 Floyd

课程表 IV【LC1462】

你总共需要上 numCourses 门课,课程编号依次为 0numCourses-1 。你会得到一个数组 prerequisite ,其中 prerequisites[i] = [ai, bi] 表示如果你想选 bi 课程,你 必须 先选 ai 课程。

  • 有的课会有直接的先修课程,比如如果想上课程 1 ,你必须先上课程 0 ,那么会以 [0,1] 数对的形式给出先修课程数对。

先决条件也可以是 间接 的。如果课程 a 是课程 b 的先决条件,课程 b 是课程 c 的先决条件,那么课程 a 就是课程 c 的先决条件。

你也得到一个数组 queries ,其中 queries[j] = [uj, vj]。对于第 j 个查询,您应该回答课程 uj 是否是课程 vj 的先决条件。

返回一个布尔数组 answer ,其中 answer[j] 是第 j 个查询的答案。

暴力

  • 暴力BFS

    class Solution {
        public List<Boolean> checkIfPrerequisite(int n, int[][] prerequisites, int[][] queries) {
            // 枚举+BFS
            List<Integer>[] g = new List[n];
            Arrays.setAll(g, e -> new ArrayList<>());
            List<Boolean> res = new ArrayList<>();
            for (int[] pre : prerequisites){
                int u = pre[0], v = pre[1];
                g[u].add(v);// v的先决条件是u
            }
            for (int[] q : queries){
                int u = q[0], v = q[1];
                Deque<Integer> queue = new LinkedList<>();
                boolean[] vis = new boolean[n];
                queue.addLast(u);
                vis[u] = true;
                boolean find = false;
                while(!queue.isEmpty()){
                    int node = queue.pollFirst();
                    if (node == v){
                        find = true;
                        break;
                    }
                    for (int next : g[node]){                   
                        if (!vis[next]){
                            queue.addLast(next);
                            vis[next] = true;
                        }
                    }
                }
                res.add(find);
            }
            return res;
        }
    }
    
    • 复杂度
      • 时间复杂度: O ( q ∗ n 2 ) \mathcal{O}(q*n^2) O(qn2)
      • 空间复杂度: O ( n 2 ) \mathcal{O}(n^2) O(n2)

Floyd

  • 思路

    • 状态定义: f [ u ] [ v ] f[u][v] f[u][v]代表节点 u u u是否至节点 v v v的先决条件

    • 状态转移:

      枚举 k k k,并枚举 u u u v v v,如果 u u u k k k的先决条件并且 k k k v v v的先决条件,那么 u u u v v v的先决条件

  • 实现

    class Solution {
        public List<Boolean> checkIfPrerequisite(int n, int[][] prerequisites, int[][] queries) {
    
            List<Boolean> res = new ArrayList<>();
            boolean[][] f = new boolean[n][n];// f[i][j]代表i是否是j的先决条件
            for (int[] pre : prerequisites){
                int u = pre[0], v = pre[1];
                f[u][v] = true;
            }
            for (int k = 0; k < n; k++){
                for (int u = 0; u < n; u++){
                    for (int v = 0; v < n; v++){
                        f[u][v] |= f[u][k] && f[k][v];
                    }
                }
            }
            for (int[] q : queries){
                int u = q[0], v = q[1];   
                res.add(f[u][v]);
            }
            return res;
        }
    }
    
    • 复杂度
      • 时间复杂度: O ( n 3 ) \mathcal{O}(n^3) O(n3)
      • 空间复杂度: O ( n 2 ) \mathcal{O}(n^2) O(n2)

拓扑排序

  • 优化思路

    • 为了每次查询时重复进行判断,使用数组记录 f [ u ] [ v ] f[u][v] f[u][v]代表节点 u u u是否至节点 v v v的先决条件;对于每个查询直接返回 f [ u ] [ v ] f[u][v] f[u][v]
    • 在拓扑排序的过程中,枚举 k k k节点是否能通过 u u u节点到达 v v v节点
  • 实现

    class Solution {
        public List<Boolean> checkIfPrerequisite(int n, int[][] prerequisites, int[][] queries) {
            // 拓扑排序
            List<Integer>[] g = new List[n];
            int[] inDeg = new int[n];
            Arrays.setAll(g, e -> new ArrayList<>());
            List<Boolean> res = new ArrayList<>();
            boolean[][] f = new boolean[n][n];// f[i][j]代表i是否是j的先决条件
            for (int[] pre : prerequisites){
                int u = pre[0], v = pre[1];
                g[u].add(v);
                inDeg[v]++;
            }
            Deque<Integer> queue = new LinkedList<>();
            for (int i = 0; i < n; i++){
                if (inDeg[i] == 0){
                    queue.addLast(i);
                }
            }
            while (!queue.isEmpty()){
                int u = queue.pollFirst();
                for (int v : g[u]){
                    f[u][v] = true;
                    for (int k = 0; k < n; k++){
                        f[k][v] |= f[k][u];//k -> u -> v 
                    }
                    if(--inDeg[v] == 0){
                        queue.addLast(v);
                    }
                }
            }
            for (int[] q : queries){
                int u = q[0], v = q[1];   
                res.add(f[u][v]);
            }
            return res;
        }
    }
    
    • 复杂度
      • 时间复杂度: O ( n 2 ) \mathcal{O}(n^2) O(n2)
      • 空间复杂度: O ( n 2 ) \mathcal{O}(n^2) O(n2)

你可能感兴趣的:(每日一题,拓扑排序,图论,算法)