图的应用之拓扑排序

拓扑排序常用于在具有先序关系的任务规划中,解决此类问题需要先把图勾画出来。
LeetCode适用题目:
207 课程安排的合法性
要求:一个课程可能会先修课程,判断给定的先修课程规定是否合法。
210 课程安排的顺序
要求:输出修完所有课程的顺序

例如:
输入:[[1,0],[2,0],[3,1],[3,2]](每个数组的第二个元素为先修课程)
输出:先修课程合法,顺序为[0,1,2,3]或者[0,2,1,3]

解题思路:先用List[]构造图,每位对应的List存储以这门课程为先修课程的课
接下来可以用DFS或者BFS。

DFS:设置全局变量标记每门课程是否已经修过, 以每个课程为起点,设置局部变量判断是否有环,如果没有环就把这门课标记,接着遍历以这门课为先修课程的所有课,如果没有环则将这门课程标记为已修.

207 课程安排的合法性的DFS解法:

public boolean canFinish(int numCourses, int[][] prerequisites) {
        List<Integer>[] graph = new List[numCourses];
        for(int i = 0;i<graph.length;i++){
            graph[i] = new ArrayList<Integer>();
        }
        boolean[] visit = new boolean[numCourses];
        for(int[] pre:prerequisites){
            graph[pre[1]].add(pre[0]);
        }
        for(int i = 0;i<numCourses;i++){
            if(!dfs(graph,visit,i,new boolean[numCourses]))
                return false;
        }
        return true;
    }
    public boolean dfs(List<Integer>[] graph,boolean[] visit,int course,boolean[] isLoop){
        if(visit[course])
            return true;
        if(isLoop[course])
            return false;
        isLoop[course] = true;
        for(int i = 0;i<graph[course].size();i++){
            if(!dfs(graph,visit,graph[course].get(i),isLoop))
                return false;
        }
        visit[course] = true;
        return true;
    }

210 课程安排的顺序的DFS解法

public int[] findOrder(int numCourses, int[][] prerequisites) {
    List<Integer>[] graphic = new List[numCourses];
    for (int i = 0; i < numCourses; i++) {
        graphic[i] = new ArrayList<>();
    }
    for (int[] pre : prerequisites) {
        graphic[pre[0]].add(pre[1]);
    }
    Stack<Integer> postOrder = new Stack<>();
    boolean[] globalMarked = new boolean[numCourses];
    boolean[] localMarked = new boolean[numCourses];
    for (int i = 0; i < numCourses; i++) {
        if (hasCycle(globalMarked, localMarked, graphic, i, postOrder)) {
            return new int[0];
        }
    }
    int[] orders = new int[numCourses];
    for (int i = numCourses - 1; i >= 0; i--) {
        orders[i] = postOrder.pop();
    }
    return orders;
}

private boolean hasCycle(boolean[] globalMarked, boolean[] localMarked, List<Integer>[] graphic,
                         int curNode, Stack<Integer> postOrder) {

    if (localMarked[curNode]) {
        return true;
    }
    if (globalMarked[curNode]) {
        return false;
    }
    globalMarked[curNode] = true;
    localMarked[curNode] = true;
    for (int nextNode : graphic[curNode]) {
        if (hasCycle(globalMarked, localMarked, graphic, nextNode, postOrder)) {
            return true;
        }
    }
    localMarked[curNode] = false;
    postOrder.push(curNode);
    return false;
}

BFS:用degree数组来存储修每门课程之前需要完成的课程数,把需要提前完成的课程数目为0的课添加到队列中,每释放队列的一个元素代表修完了一门课程,然后遍历以这门课程为先决课程的课,对应的degree减一,当degree为0时表示这门课也可以修了,就把它添加到队列中。

207 课程安排的合法性的BFS解法:

public boolean canFinish(int numCourses, int[][] prerequisites) {
        List<Integer>[] graph = new List[numCourses];
        for(int i = 0;i<graph.length;i++){
            graph[i] = new ArrayList<Integer>();
        }
        int[] degree = new int[numCourses];
        for(int[] pre:prerequisites){
            degree[pre[0]]++;
            graph[pre[1]].add(pre[0]);
        }
        Queue<Integer> queue = new LinkedList<Integer>();
        for(int i = 0;i<numCourses;i++){
            if(degree[i]==0)
                queue.offer(i);
        }
        int visit = 0;
        while(!queue.isEmpty()){
            int from = queue.poll();
            visit++;
            for(int to:graph[from]){
                degree[to]--;
                if(degree[to]==0)
                    queue.offer(to);
            }
        }
        return visit==numCourses?true:false;
    }

210 课程安排的顺序的BFS解法

public int[] findOrder(int numCourses, int[][] prerequisites) {
        int[] ans = new int[numCourses];
        List<Integer>[] graph = new List[numCourses];
        for(int i = 0;i<graph.length;i++){
            graph[i] = new ArrayList<Integer>();
        }
        int[] degree = new int[numCourses];
        for(int[] pre:prerequisites){
            degree[pre[0]]++;
            graph[pre[1]].add(pre[0]);
        }
        Queue<Integer> queue = new LinkedList<Integer>();
        for(int i = 0;i<numCourses;i++){
            if(degree[i]==0)
                queue.add(i);
        }
        int visit = 0;
        while(!queue.isEmpty()){
            int from = queue.poll();
            ans[visit++] = from;
            for(int to:graph[from]){
                degree[to]--;
                if(degree[to]==0)
                    queue.add(to);
            }
        }
        return visit==numCourses?ans:new int[0];
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值