java数据结构与算法刷题-----LeetCode210. 课程表 II

java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.youkuaiyun.com/grd_java/article/details/123063846

在这里插入图片描述

这道题是207题的衍生题,代码完全一样,具体解析看207题即可,这里不做过多赘述了。

🏆LeetCode207. 课程表(拓扑排序)https://blog.youkuaiyun.com/grd_java/article/details/137561889

深度优先遍历但不进行逆拓扑排序(不用栈)

解题思路:时间复杂度O( m + n m+n m+n),空间复杂度O( m + n m+n m+n)n是顶点数,m是边的数量
  1. 有了207题的基础,我们知道,深度优先遍历的拓扑排序输出结果是逆拓扑排序
  2. 如果我们想要正着输出,目前经典的解决方法,是先将结果放入栈中,最后完成排序后,再次出栈完成输出,实现逆拓扑排序反转效果
  3. 但是我们不使用栈如何实现呢?那就是逆中逆的思路
  4. 我们保存所有顶点的直接前驱顶点(指向它的顶点),然后逆过了,从每个顶点向上深度优先遍历,将它所有的前驱顶点处理完成,当前顶点就是0入度顶点
  5. 这样就完成了深度优先遍历,直接按照正拓扑排序顺序输出的效果
  6. 具体可以看207题的解析,有详细案例
代码:这种算法比普通的深度优先和广度优先算法更快

在这里插入图片描述

class Solution {
    static class Node {//课程结点,用来抽象为图
        Node next;//当前结点指向的下一个结点
        int val;//值
        public Node(){
            this.val = -1;
        }
        public Node(int val){
            this.val = val;
        }
        public Node(int val,Node next){
            this.val = val;
            this.next = next;
        }
    }
    Node[] corses;//保存每个顶点的前驱结点(哪些顶点指向当前顶点)
    int[] visited;//0:未访问,1:已访问,2:已经拓扑遍历
    int[] ans;//保存拓扑排序结果
    int ansIndex;//下标
    public int[] findOrder(int numCourses, int[][] prerequisites) {
        corses = new Node[numCourses];//初始化
        visited = new int[numCourses];//初始化
        ans = new int[numCourses];//初始化
        ansIndex = 0;//初始化
        for(int[] corse:prerequisites){
            //要完成corse[0],必须先完成corse[1],也就是corse[1]->corse[0].所以corse[0]的前驱需要添加一个corse[0]
            corses[corse[0]]=new Node(corse[1],corses[corse[0]]);//头插法将corse[1]插入到corse[0]顶点的前驱链表中
        }
        for(int i = 0; i < numCourses; i++){//依次试图从每个顶点进行深度优先遍历
            if(!dfs(i)) return new int[]{};//如果无法完成拓扑排序,就返回空数组
        }
        return ans;//完成拓扑排序,返回拓扑排序结果
    }
    private boolean dfs(int i){//深度优先遍历
        if(visited[i] == 2)return true;//如果当前顶点已经拓扑输出,直接跳过
        if(visited[i] == 1)return false;//如果当前顶点没有拓扑输出,但是再次访问,说明有环,不能完成拓扑排序
        visited[i] = 1;//标志为已经访问过
        Node node = corses[i];//获取当前顶点的所有直接前驱邻居
        while(node!=null){
            if(!dfs(node.val)) return false;//访问这些前驱,直到它们没有前驱为止,说明它是一个0入的顶点
            node = node.next;//处理当前顶点所有的直接前驱后
        }
        visited[i] = 2;//当前顶点就没有入度了(因为前驱全部被输出处理了)
        ans[ansIndex++] = i;//将其输出
        return true;//表示到目前位置,满足拓扑排序
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ydenergy_殷志鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值