算法——图论:拓扑排序

. - 力扣(LeetCode)

你这个学期必须选修 numCourses 门课程,记为 0numCourses - 1

在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai必须 先学习课程 bi

  • 例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1

请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false

即图中不能有环。

注意邻接表和邻接矩阵的转换。

自己的解法:拓扑排序,找出每个节点前面节点的个数,不断遍历将值为零的访问。

类似广度优先搜索,不过不完全一样,未使用队列,时间复杂度较高。

复制代码
class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        if(prerequisites.size()==0)return true;
        vector<long long> pre(numCourses,0);
        vector<int> visited(numCourses,0);
        for(int i=0;i<prerequisites.size();i++)
        {
            int  a=prerequisites[i][0],b=prerequisites[i][1];
            pre[a]++;
        }
        int maxcou=numCourses;
        while(maxcou--)
        {
            for(int i=0;i<numCourses;i++)
            {
                if(visited[i]==0&&pre[i]==0)
                {
                    visited[i]=1;
                    for(int j=0;j<prerequisites.size();j++)
                    {
                        if(prerequisites[j][1]==i)
                        pre[prerequisites[j][0]]--;
                    }
                }
            }
        }
        for(int i=0;i<numCourses;i++)
        {
            if(visited[i]==0)return false;
        }        
        return true;
    }
};

注意:在while循环中判断条件为课程数量,即最多可能循环这么多次。考虑极端情况:

5->4->3->2->1,第一次到最后才找到5,第二次到最后才找到4,这样每次循环只能访问一个节点。需n次。若为1->2->3->4->5,则仅需一次即可访问全部节点。

题目中使用的是邻接矩阵,或者转换一下使用邻接表,会更方便。

官方题解:

1.深搜

复制代码
class Solution {
private:
    vector<vector<int>> edges;
    vector<int> visited;
    bool valid = true;

public:
    void dfs(int u) {
        visited[u] = 1;
        for (int v: edges[u]) {
            if (visited[v] == 0) {
                dfs(v);
                if (!valid) {
                    return;
                }
            }
            else if (visited[v] == 1) {
                valid = false;
                return;
            }
        }
        visited[u] = 2;
    }

    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        edges.resize(numCourses);
        visited.resize(numCourses);
        for (const auto& info: prerequisites) {
            edges[info[1]].push_back(info[0]);
        }
        for (int i = 0; i < numCourses && valid; ++i) {
            if (!visited[i]) {
                dfs(i);
            }
        }
        return valid;
    }
};

2.广搜

使用一个队列;将邻接矩阵转化为邻接表。

复制代码
class Solution {
private:
    vector<vector<int>> edges;
    vector<int> indeg;

public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        edges.resize(numCourses);
        indeg.resize(numCourses);
        for (const auto& info: prerequisites) {
            edges[info[1]].push_back(info[0]);
            ++indeg[info[0]];
        }

        queue<int> q;
        for (int i = 0; i < numCourses; ++i) {
            if (indeg[i] == 0) {
                q.push(i);
            }
        }

        int visited = 0;
        while (!q.empty()) {
            ++visited;
            int u = q.front();
            q.pop();
            for (int v: edges[u]) {
                --indeg[v];
                if (indeg[v] == 0) {
                    q.push(v);
                }
            }
        }

        return visited == numCourses;
    }
};
相关推荐
wuqingshun3141592 小时前
蓝桥杯 冶炼金属
算法·职场和发展·蓝桥杯
jndingxin4 小时前
OpenCV CUDA模块光流计算-----实现Farneback光流算法的类cv::cuda::FarnebackOpticalFlow
人工智能·opencv·算法
编程绿豆侠4 小时前
力扣HOT100之栈:394. 字符串解码
java·算法·leetcode
朝朝又沐沐4 小时前
基于算法竞赛的c++编程(18)string类细节问题
开发语言·c++·算法
爱coding的橙子5 小时前
每日算法刷题Day27 6.9:leetcode二分答案2道题,用时1h20min
算法·leetcode·职场和发展
GalaxyPokemon5 小时前
LeetCode - 3. 无重复字符的最长子串
算法·哈希算法·散列表
a.3025 小时前
C++ 时间处理指南:深入剖析<ctime>库
数据结构·c++·算法
亮亮爱刷题6 小时前
算法刷题-回溯
算法
Neil今天也要学习6 小时前
永磁同步电机无速度算法--自适应龙贝格观测器
算法