记录:2022-10-3 课程表 II 拓扑排序

学习时间:2022-10-3

学习内容

1、leetcode

210. 课程表 II

在这里插入图片描述

思路

一道拓扑排序的题目,可以说是很典型,几种情况全部考虑到了。主要需要想到为什么可以用拓扑排序来做的问题

代码
class Solution {
    public int[] findOrder(int numCourses, int[][] prerequisites) {
        int[] in = new int[numCourses];
        LinkedList<Integer> queue = new LinkedList<Integer>();
        ArrayList<Integer> ans = new ArrayList<Integer>();
        HashMap<Integer,ArrayList<Integer>> edge = new HashMap<Integer,ArrayList<Integer>>();
        for(int i = 0;i<prerequisites.length;i++){
            //构成一个图
            int[] prerequisite = prerequisites[i];
            in[prerequisite[0]]++;
            ArrayList<Integer> list = edge.getOrDefault(prerequisite[1],new ArrayList<Integer>());
            list.add(prerequisite[0]);
            edge.put(prerequisite[1],list);
        }
        for(int i = 0;i<numCourses;i++){
            if(in[i] == 0){
                queue.add(i);
                continue;
            }
        }
        while(!queue.isEmpty()){
            int node = queue.poll();
            ans.add(node);
            ArrayList<Integer> edges = edge.getOrDefault(node,new ArrayList<Integer>());
            for(int i = 0;i<edges.size();i++){
                int to = edges.get(i);
                if(--in[to] == 0){
                    queue.add(to);
                }
            }
        }
        int[] res = new int[ans.size()];
        for(int i = 0;i<ans.size();i++){
            res[i] = ans.get(i);
        }
        if(res.length != numCourses) return new int[]{};
        return res;
    }
}

在这里插入图片描述

更优解

一个用时2ms的解法,没有出现在官解上,思路大概一致

class Solution {
    int M, N;
    int[] e, ne;
    int[] he, in;
    int idx;

    public void add(int a, int b) {
        e[idx] = b;
        ne[idx] = he[a];
        he[a] = idx++;
        in[b]++;
    }

    public void initGraph(int numCourses, int[][] prerequisites) {
        M = prerequisites.length;
        N = numCourses;
        e = new int[M];
        ne = new int[M];
        he = new int[N];
        in = new int[N];
        Arrays.fill(he, -1);
        for (int[] prerequisite : prerequisites) {
            add(prerequisite[1], prerequisite[0]);
        }
    }

    public int[] findOrder(int numCourses, int[][] prerequisites) {
        int[] result = new int[numCourses];

        // 初始化图
        initGraph(numCourses, prerequisites);

        // 选出入度为 0 的节点
        Queue<Integer> queue = new LinkedList<>();
        for (int i = 0; i < numCourses; i++) {
            if (in[i] == 0) {
                queue.offer(i);
            }
        }

        // 拓扑排序, 保存任意结果
        int cnt = 0;
        while (!queue.isEmpty()) {

            int sz = queue.size();
            for (int i = 0; i < sz; i++) {
                int t = queue.poll();
                result[cnt++] = t;

                for (int j = he[t]; j != -1; j = ne[j]) {
                    if (--in[e[j]] == 0) {
                        queue.offer(e[j]);
                    }
                }

            }

        }

        return cnt == numCourses ? result : new int[0];
    }
}

2、拓扑排序

拓扑排序需要构建一个图,这种排序一般是有向的,需要in和edge,还有一个queue来存当前入队的节点
给定一个包含 n 个节点的有向图 GG,我们给出它的节点编号的一种排列,如果满足:
对于图 G 中的任意一条有向边 (u, v),u 在排列中都出现在 v 的前面。
那么称该排列是图 G 的「拓扑排序」。

经典代码:

queue<int>q;
    vector<int>edge[n];
    for(int i=0;i<n;i++)  //n  节点的总数
        if(in[i]==0) q.push(i);  //将入度为0的点入队列
    vector<int>ans;   //ans 为拓扑序列
    while(!q.empty())
    {
        int p=q.front(); q.pop(); // 选一个入度为0的点,出队列
        ans.push_back(p);
        for(int i=0;i<edge[p].size();i++)
        {
            int y=edge[p][i];
            in[y]--;
            if(in[y]==0)
                q.push(y);  
        }
    }
    if(ans.size()==n)   
    {
        for(int i=0;i<ans.size();i++)
            printf( "%d ",ans[i] );
        printf("\n");
    }
    else printf("No Answer!\n");   //  ans 中的长度与n不相等,就说明无拓扑序列
————————————————
版权声明:本文为CSDN博主「独-」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_41713256/article/details/80805338

若要求字典序最小,把队列换成优先队列

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值