LeetCode week 12 : Course Schedule

题目

地址: https://leetcode.com/problems/course-schedule/description/
类别: Topological Sort
难度: Medium
描述:

There are a total of n courses you have to take, labeled from 0 to n - 1.

Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]

Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?

For example:

2, [[1,0]]

There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible.

2, [[1,0],[0,1]]

There are a total of 2 courses to take. To take course 1 you should have finished course 0, and to take course 0 you should also have finished course 1. So it is impossible.

分析

给定n个课程(0~n-1)供学生学习, 学生学习课程有先后限制,限制[i,j]表示学习课程i之前必须学习完课程j。
现给出n个课程及课程之间的限制关系,判断学生是否可以按照某一学习顺序学习完所有课程。
例:

Input:
课程数:3
限制:[[1,0],[2,1]]
Output:
true(0->1->2)

Input:
课程数:3
限制:[[1,0],[2,1],[0,2]]
Output:
false

不难发现输入可以转化为有向图,而转化后的图中只要有环,必定存在不能满足的依赖,即环中的课程都相互依赖导致无法学习,最后无法学完所有课程。因此原问题可转化为判断等价有向图中是否存在环。

思路

方法:拓扑排序
目标:判断有向图是否可拓扑排序(是否无环)。
为了便于拓扑排序时的操作,我们先将原输入转化为邻接链表

    vector<unordered_set<int>> convertToAdjacencyLists(int numCourses, vector<pair<int, int>>& prerequisites) {
        vector<unordered_set<int>> AdjacencyLists(numCourses);
        for(auto pre : prerequisites)
            AdjacencyLists[pre.first].insert(pre.second);
        return AdjacencyLists;
    }

然后计算每个顶点的入度:

    vector<int> computeIndegree(int numCourses, vector<unordered_set<int>>& AdjacencyLists) {
        vector<int> inDegrees(numCourses, 0);
        for(auto outNeighbors : AdjacencyLists)
            for(auto n : outNeighbors)
                inDegrees[n]++;
        return inDegrees;
    }

最后进行拓扑排序判断:

1.  若有向图中不存在入度为0的顶点,则必定存在环,返回false;否则任意选择一个入度为0的顶点q;
2.  从图中删除q点和所有以它为起点的边;
3.  重复1和2至删除掉所有顶点结束或在1的过程中不存在入度为0的顶点中断为止。

代码:

class Solution {
public:
    bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
        vector<unordered_set<int>> AdjacencyLists = convertToAdjacencyLists(numCourses, prerequisites); 
        vector<int> inDegrees = computeIndegree(numCourses, AdjacencyLists);
        queue<int> Q;
        for(int i = 0; i < numCourses; i++)
            if(inDegrees[i] == 0)
                Q.push(i);
        int count = 0;
        while(!Q.empty()) {
            int q = Q.front();
            Q.pop();
            count++;
            for(auto outNeighbor : AdjacencyLists[q])
                if(!(--inDegrees[outNeighbor]))
                    Q.push(outNeighbor);
        }
        return (count == numCourses);

    }
private:
    vector<int> computeIndegree(int numCourses, vector<unordered_set<int>>& AdjacencyLists) {
        vector<int> inDegrees(numCourses, 0);
        for(auto outNeighbors : AdjacencyLists)
            for(auto n : outNeighbors)
                inDegrees[n]++;
        return inDegrees;
    }
    vector<unordered_set<int>> convertToAdjacencyLists(int numCourses, vector<pair<int, int>>& prerequisites) {
        vector<unordered_set<int>> AdjacencyLists(numCourses);
        for(auto pre : prerequisites)
            AdjacencyLists[pre.first].insert(pre.second);
        return AdjacencyLists;
    }
};

简化:
如果忽略模块化的话,可以将在建立邻接链表的同时求出入度

class Solution {
public:
    bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
        vector<int> inDegrees(numCourses, 0);
        vector<unordered_set<int>> AdjacencyLists = convertToAdjacencyLists(numCourses, prerequisites, inDegrees); 
        queue<int> Q;
        for(int i = 0; i < numCourses; i++)
            if(inDegrees[i] == 0)
                Q.push(i);
        int count = 0;
        while(!Q.empty()) {
            int q = Q.front();
            Q.pop();
            count++;
            for(auto outNeighbor : AdjacencyLists[q])
                if(!(--inDegrees[outNeighbor]))
                    Q.push(outNeighbor);
        }
        return (count == numCourses);
    }
private:
    vector<unordered_set<int>> convertToAdjacencyLists(int numCourses, vector<pair<int, int>>& prerequisites, vector<int> & inDegrees) {
        vector<unordered_set<int>> AdjacencyLists(numCourses);
        for(auto pre : prerequisites) {
            AdjacencyLists[pre.first].insert(pre.second);
            inDegrees[pre.second]++;
        }
        return AdjacencyLists;
    }
};

注:在实现代码的时候用队列或栈保存0入度点都是可以的,因为同时存在在里面的点之间没有关系。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值