图论总结

本文详细介绍了图论中的拓扑排序、欧拉图、并查集、最小生成树、回溯算法和多源最短路等概念,结合具体算法如Hierholzer、Kruskal和Floyd,并给出了力扣相关题目作为实践示例。
摘要由CSDN通过智能技术生成

拓扑排序

拓扑排序的本质是:广度优先遍历 + 贪心算法。
拓扑排序是广度优先遍历和贪心算法应用于有向图的专有名词。
应用场景:任务调度计划、课程安排。
拓扑排序的作用:
1.得到一个拓扑序,拓扑序不唯一;
2.检测有向图是否有环。(补充:无向图中检测是否有环,使用的数据结构是并查集。)
算法流程:
1、在开始排序前,扫描对应的存储空间(使用邻接表),将入度为 0的结点放入队列。
2、只要队列非空,就从队首取出入度为 0 的结点,将这个结点输出到结果集中,并且将这个结点的所有邻接结点(它指向的结点)的入度减 1,在减 1 以后,如果这个被减 1的邻接结点的入度为 0,则入队。
3、当队列为空的时候,检查结果集中的顶点个数是否和图的顶点数相等即可。

在代码具体实现的时候,除了保存入度为 0 的队列,我们还需要两个辅助的数据结构:
1、邻接表:通过结点的索引,我们能够得到这个结点的后继结点;
2、入度数组:通过结点的索引,我们能够得到指向这个结点的结点个数。

力扣相关题目

1.207. 课程表
代码如下:

class Solution {
   
    public boolean canFinish(int numCourses, int[][] prerequisites) {
   
        if (numCourses < 0) {
   
            return false;
        }
        if (null == prerequisites || 0 == prerequisites.length || 0 == prerequisites[0].length) {
   
            return true;
        }
        // 入度数组
        int[] inDegree = new int[numCourses];
        // 图的邻接表实现
        HashSet<Integer>[] adj = new HashSet[numCourses];
        for (int i = 0; i < numCourses; i ++) {
   
            adj[i] = new HashSet<>();
        }
        for (int[] p : prerequisites) {
   
            inDegree[p[0]] ++;
            adj[p[1]].add(p[0]);
        }
        // 队列:java推荐实现
        Queue<Integer> queue = new LinkedList<>();
        // 找到一开始入度为0的顶点
        for (int i = 0; i < numCourses; i ++) {
   
            if (inDegree[i] == 0) {
   
                queue.add(i);
            }
        }
        int cnt = 0;
        while (!queue.isEmpty()) {
   
            Integer top = queue.poll();
            cnt ++;
            for (Integer successor : adj[top]) {
   
                inDegree[successor] --;
                if (inDegree[successor] == 0) {
   
                    queue.add(successor);
                }
            }
        }
        return cnt == numCourses;
    }
}

2.210. 课程表 II

// 拓扑排序的模板
class Solution {
   
    public int[] findOrder(int numCourses, int[][] prerequisites) {
   
        int[] res = new int[numCourses];
        if (numCourses < 0 ) {
   
            return res;
        }
        if ((null == prerequisites || 0 == prerequisites.length || 0 == prerequisites[0].length)) {
   
            for (int i = 0; i < numCourses; i++) {
   
                res[i] = numCourses - i - 1;
            }
            return res;
        }
        int[] inDegree = new int[numCourses];
        HashSet<Integer>[] adj = new HashSet[numCourses];
        for (int i = 0; i < numCourses; i ++) {
   
            adj[i] = new HashSet<>();
        }
        for (int[] p : prerequisites) {
   
            inDegree[p[0]] ++;
            adj[p[1]].add(p[0]);
        }
        
        Queue<Integer> queue = new LinkedList<>();
        for (int i = 0; i < numCourses; i ++) {
   
            if (inDegree[i] == 0) {
   
                queue.offer(i);
            }
        }
        int cnt = 0;
        while (!queue.isEmpty()) {
   
            Integer top = queue.poll();
            res[cnt ++] = top;
            for (Integer successor : adj[top]) {
   
                inDegree[successor] --;
                if (inDegree[successor] == 0) {
   
                    queue.add(successor);
                }
            }
        }
        return cnt == numCourses ? res : new int[0];
    }
}

3.802. 找到最终的安全状态
参考资料
代码如下:

class Solution {
   
    public List<Integer> eventualSafeNodes(int[][] graph) {
   
        int N = graph.length;
        List<Set<Integer>> gra = new ArrayList<>();
        List<Set<Integer>> rgra = new ArrayList
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值