• 207. 课程表


    题目

    207. 课程表

    我的思路

    经过分析,本题似乎等价于判断一个图中是否存在环。我的朴素思路是,先把图用数据结构表示起来,然后依次对每个节点深搜,当路径长于图中的节点数时,说明存在环。

    在实现上有许多地方可以改进,值得推敲。首先我在实现时是用链表表示有向图的,可以用更适合图(而非树)的邻接表来表示。其次我在深搜时,没有进行记忆化处理。最后,在判断是否存在环时用路径长度作为判断标准效率也很低。

    下面整理一下官方题解的思路。

    首先本题等价于判断是否存在“拓扑排序”问题。而由拓扑排序相关算法的性质,等价于寻找一个“拓扑排序”的问题。这类问题是有套路和模板的。

    不论深搜还是广搜,核心思路是不断地寻找并访问入度为0的节点(安全节点)。

    思路一:深搜

    所有的节点有三种状态,未访问,访问过,和正在访问。当搜索到正在访问的节点时说明有环。

    递归思路:把当前访问的节点设置为正在访问状态,遍历当前节点指向的所有节点,若遍历完毕,把当前节点设为已访问。尽管此题目不需要,但是可以在标记节点为已访问时,把该节点入栈,这个栈可以作为一种拓扑排序!

    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;
        }
    };
    
    作者:LeetCode-Solution
    链接:https://leetcode-cn.com/problems/course-schedule/solution/ke-cheng-biao-by-leetcode-solution/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    思路二:广搜(非递归)

    广搜需要从入度为0,也就是拓扑排序中可以可以直接作为首元素的节点开始搜索。用一个辅助数组记录所有节点的入度数。

    循环:把入度为0的节点加入队列,取队首,消除与队首有关的边(把辅助数组中相关节点的入度数-1)。取队首时可以把它加入结果队列,最后形成一个“拓扑排序”。出循环的条件是直到队列为空,比较结果队列的长度和节点数即可得知是否存在“拓扑排序”。

    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;
        }
    };
    
    作者:LeetCode-Solution
    链接:https://leetcode-cn.com/problems/course-schedule/solution/ke-cheng-biao-by-leetcode-solution/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    我的实现

    class Solution {
    public:
        struct TreeNode{
        int val;
        vector<TreeNode*> Children;
        TreeNode(int v):val(v),Children(){};
    };
        bool search(TreeNode *presentRoot,int count,const int & max){
            if(count>max){
                return false;
            }
            for(auto it: presentRoot->Children)
            {
                if(false==search(it,count+1,max))return false;
            }
            return true;
    
        }
        bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
            vector<TreeNode*> allcourses;
            TreeNode *temp;
            for(int i=0;i<numCourses;i++)
            {
                temp = new TreeNode(i);
                allcourses.push_back(temp);
            }
            for(auto it: prerequisites)
            {
                //cout<<it[0]<<it[1]<<endl;
                (allcourses[it[0]]->Children).push_back(allcourses[it[1]]);
            }
            for(auto it: allcourses)
            {
                if(search(it,0,numCourses)==false)return false;
            }
            return true;
        }
    };
    
    /*
    好像就是等效于检测是否存在环(a,b) (b..,..z) (z,a)
    深搜?
    struct TreeNode{
        int val;
        vector<TreeNode*> Children;
        TreeNode(v):val(v),Children():{};
    }
    1.为prerequisites中出现的匹配建造一些树
    2.深搜每一个非叶子节点,若出现环,那么返回false;如果没有环,那么true
    */

    拓展学习

    拓扑排序

    邻接表

  • 相关阅读:
    注解-案例
    注解(Annotation)
    适合新手看的超详细CentOS Linux 7 安装Tomcat8过程
    CentOS Linux 7 提示 lsof: 未找到命令
    解决MySql报错:1130
    Spring Boot 创建自定义的properties文件
    spring boot 使用Schedule创建轻量级定时任务
    4.Java数组模块
    3.IDEA开发工具
    2.java基础语法
  • 原文地址:https://www.cnblogs.com/BoysCryToo/p/13432520.html
Copyright © 2020-2023  润新知