• 207.课程表


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

    在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]

    给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习?

    示例2:

    输入: 2, [[1,0],[0,1]]
    输出: false
    解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成​课程 0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。
    

    方法一:BFS

    分析:

    这道题即判断一个有向图中是否有环,可以用拓扑排序算法来解决。过程如下:
    1.从有向图中选择没有前驱(入度为0)的顶点输出。
    2.依次删除1中的顶点,并删除这些顶点发出的全部边。
    3.重复上述2步,直到图中不存在没有前驱的顶点为止。若此时还有顶点剩余则说明图中有环。
    这道题还需要考虑的一个关键问题是如何表示图。
    
        bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
            //建立图,graph[i]包含所有结点i指向的结点,有点类似图的邻接表存储结构
            vector<vector<int>> graph(numCourses,vector<int>());
            //记录每个结点的入度
            vector<int> in(numCourses,0);
            for(auto i:prerequisites){
                graph[i[1]].push_back(i[0]);
                in[i[0]]++;
            }
            queue<int> q;
            for(int i=0;i<numCourses;++i){
                if(in[i]==0)q.push(i);
            }
            while(!q.empty()){
                int front=q.front();
                q.pop();
                for(auto i:graph[front]){
                    in[i]--;
                    if(in[i]==0) q.push(i);
                }
            }
            //如果还有结点的入度不为0,则说明图中存在环
            for(int i=0;i<numCourses;++i)
                if(in[i]!=0) return false;
            return true;
        }
    

    方法二:DFS

    分析:

    需要使用一个访问数组来记录当前节点的访问情况。访问数组的取值:
    0:未被访问
    1:已经被访问,即完成回溯
    -1:正在被访问,还未回溯完成
    具体过程:
    深度优先遍历访问每个节点。在使用深度优先遍历访问数组的时候先将当前节点的访问状态置为-1,表示正在访问该节点。然后递归的去访问该节点所有指向的节点。最后将该节点的访问状态置为1,表示已经访问过了。在递归访问节点的过程中只要发现当前待访问节点的访问状态为-1,则表示出现了环;若访问状态为1,则无需在访问该节点。
    
        bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
            vector<vector<int>> graph(numCourses, vector<int>());
            vector<int> visit(numCourses);
            for (auto a : prerequisites) {
                graph[a[1]].push_back(a[0]);
            }
            //注意这里是有向图,当且仅当所有结点都能回溯到自身位置才能说明图中不存在环
            for (int i = 0; i < numCourses; ++i) {
                if (!canFinishDFS(graph, visit, i)) return false;
            }
            return true;
        }
        //返回值表示从结点i开始是否能完成深度优先搜索并回溯到原点
        bool canFinishDFS(vector<vector<int>>& graph, vector<int>& visit, int i) {
            //当某个结点还未完成回溯时又被访问,说明图中存在环
            if (visit[i] == -1) return false;
            //因为canFinish函数中对所有结点都调用了该函数,因此在此之前可能该结点被访问过且能够回溯到原点,加入这一行可减少运行时间
            if (visit[i] == 1) return true;
            //正在被访问
            visit[i] = -1;
            for (auto a : graph[i]) {
                if (!canFinishDFS(graph, visit, a)) return false;
            }
            //回溯到原点表示访问完成
            visit[i] = 1;
            return true;
        }
    
  • 相关阅读:
    【leetcode】106. Construct Binary Tree from Inorder and Postorder Traversal
    【leetcode】105. Construct Binary Tree from Preorder and Inorder Traversal
    【leetcode】236. Lowest Common Ancestor of a Binary Tree
    【leetcode】235. Lowest Common Ancestor of a Binary Search Tree
    【leetcode】352. Data Stream as Disjoint Intervals
    【leetcode】897. Increasing Order Search Tree
    【leetcode】900. RLE Iterator
    BEC listen and translation exercise 26
    BEC listen and translation exercise 25
    BEC listen and translation exercise 24
  • 原文地址:https://www.cnblogs.com/Frank-Hong/p/13326754.html
Copyright © 2020-2023  润新知