课程表[拓扑排序]

前言

给定一些边信息,要得到拓扑排序,得学会把图的物理结构做出来,再进行层序遍历。

一、课程表

在这里插入图片描述

二、拓扑排序

package everyday.graph;

import java.util.*;

// 课程表
public class CanFinish {
    /*
    给定了有向边,看是否能得到拓扑排序。
    拓扑排序:1-构造图 + 入度数组;2-层序遍历即可;3-记录出队列的数量是否等于numCourses;
     */
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        // 入度数组
        int[] inDegree = new int[numCourses];
        // 构建邻接表。
        for (int[] prerequisite : prerequisites) {
            addEdge(prerequisite[0], prerequisite[1]);
            inDegree[prerequisite[0]]++;
        }


        return getNodeCount(inDegree) == numCourses;
    }

    public int getNodeCount(int[] inDegree) {
        int numCourses = inDegree.length;
        // 层序遍历
        Queue<Integer> que = new ArrayDeque<>();
        // 寻找入度为0的节点加入。
        for (int i = 0; i < numCourses; i++) if (inDegree[i] == 0) que.add(i);
        // 开始拓扑排序。
        int count = 0;
        while (!que.isEmpty()) {
            int cur = que.poll();
            // 记录出队列节点数。
            ++count;
            // 撤销cur节点,让next节点的入度减一。
            Set<Integer> nodes = graph.get(cur);
            // bug1:nodes为null,是不可以这样循环的,这样nodes.会调迭代器,会出现空指针异常。
            if (nodes == null) continue;

            for (Integer node : nodes) {
                if (--inDegree[node] == 0) que.add(node);
            }
        }
        return count;
    }

    // 构建图的邻接表。
    private void addEdge(int behind, int front) {
        // 添加节点
        addNode(behind);
        addNode(front);
        // 设置有向边
        graph.get(front).add(behind);
    }

    // 填加节点
    private void addNode(int node) {
        if (!graph.containsKey(node)) graph.put(node, new HashSet<>());
    }

    // 用Map来作为邻接表的物理结构。
    Map<Integer, Set<Integer>> graph = new HashMap<>();

}

总结

1)对于图问题,建图的物理结构 + 图的遍历是基础,需熟练掌握邻接表的建立 + DFS + BFS。

参考文献

[1] LeetCode 课程表

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值