【LeetCode207】-课程表

方法一(DFS)

实现思路

将所有的关系抽象为有向图,图的结点代表的是课程,有向边代表的是两者之间的先后关系
核心思想: DFS+访问状态

访问状态的设置:
(1)-1代表没有访问
(2)0代表当前正在访问的结点
(3)1代表已经访问过
大体步骤:
(一)初始化,初始化所有结点的初始访问状态为-1,建立邻接表
(二)遍历所有尚未访问的点进行DFS,此时如果DFS返回false代表有环,否则都遍历完返回true

DFS的核心逻辑
DFS初始时标记当前的结点状态为0,遍历完所有邻居结点后状态设置为-1
在遍历邻居结点的过程中有两种情况返回false
(1)邻居结点状态为0,说明有环
如:0->2,2>0


(2)邻居结点尚未访问,依着该结点往下DFS的时候返回结果为false,说明接下来遍历后出现了环
如:1->2->3->1


实现代码

struct GraphNode{
    
    
    int val;
    vector<int> neighbor;
};
class Solution {
    
    
public:
 
    bool DFS(GraphNode*t,vector<int> &vis,vector<GraphNode*> &data){
    
    
        vis[t->val]=0;
        for(int i=0;i<t->neighbor.size();i++){
    
    
            if(vis[data[t->neighbor[i]]->val]==0){
    
    
                return false;
            }
            else if(vis[data[t->neighbor[i]]->val]==-1){
    
    
                if(DFS(data[t->neighbor[i]],vis,data)==false){
    
    
                return false;
                }
            }
        }
        vis[t->val]=-1;
        return true;
    }
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
    
    
        //初始化所有访问的结点状态为-1
        vector<int> vis(numCourses,-1);
        vector<GraphNode*> data(numCourses);
        //初始化邻接表
        for(int i=0;i<numCourses;i++){
    
    
            GraphNode *t=new GraphNode;
            t->val=i;
            data[i]=t;
        }
        for(auto i:prerequisites){
    
    
            int x1=i[0];
            int x2=i[1];
            data[x1]->neighbor.push_back(x2);
        }
        for(auto item:data){
    
    
            if(item!=nullptr)
            {
    
    
                if(vis[item->val]==-1&&DFS(item,vis,data)==false){
    
    
                return false;
                }
            }
        }
        for(int i=0;i<data.size();i++){
    
    
            delete data[i];
        }
        return true;
    }
};

提交结果及分析

在这里插入图片描述

方法二(BFS)

实现思想

核心思想: BFS+入度
在这里插入图片描述在这里插入图片描述主要思想是结合了宽度搜索和入度的概念,一个结点的入度代表的是它当前所需要依赖的先修课程,当先修课程可以修时被依赖的课程入度就可以减一,当所有结点的入度都为0时说明所有课程都可以修完

实现代码

struct Node{
    
    
    int val;
    vector<Node*> neighbor;
    Node(int val){
    
    
        this->val=val;
    }
};
class Solution {
    
    
public:

    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
    
    
        vector<int> gin(numCourses,0);
        vector<Node*> graph(numCourses);
        for(int i=0;i<numCourses;i++){
    
    
            graph[i]=new Node(i);
        }
        for(auto item:prerequisites){
    
    
            int x1=item[0];
            int x2=item[1];
            graph[x2]->neighbor.push_back(graph[x1]);
            gin[x1]++;
        }
        for(int j=0;j<numCourses;j++){
    
    
        for(int i=0;i<numCourses;i++){
    
    
            if(gin[i]==0){
    
    
                gin[i]=-1;
                for(auto item:graph[i]->neighbor){
    
    
                    gin[item->val]--;
                }
            }
        }
        }
        for(int i=0;i<numCourses;i++){
    
    
            // cout<<gin[i]<<endl;
            if(gin[i]>0)
            return false;
        }
        return true;
    }
};

在这里插入图片描述代码二里面在进行减度操作的时候利用队列将度为0的点压入队列中,从队列中取出点对其临近的点减度操作,发现有新的点的度为0就将其压入队列中,其实这种思想类似于Bellman-floyd改进方法SPFA的思想,只有度变为0才考虑其相邻的结点

提交结果及分析

代码一
在这里插入图片描述
时间复杂度O(n^2+m)n为结点个数,m为边的个数

总结

DFS的思想更加抽象,抽离出了问题单纯只考虑有没有环即可
BFS的思想其实跟贴近题目,通俗理解就是能修的课程先修了,每个课程能修的前提考虑它的先修课程都修完了,这里面复习了一个重要入度的概念也要记住

猜你喜欢

转载自blog.csdn.net/weixin_44944046/article/details/114336077
今日推荐