力扣--课程表--bfs+dfs

news/2024/6/29 12:01:35 标签: 深度优先, leetcode, 宽度优先

整体思路:

 这是一道拓扑序列的题目,我们将边的方向定义成从先修课指向后修课的方向,借一下官方的题解图片,我们需要判断的是形成的这个图结构是否存在环,如果存在环,那么代表不能完成所有课程的学习。

bfs思路:

首先将每个点的入度数记录到hmap中,将每个点的后续节点记录到record中(record是一个unordered_map<int,vector<int>>结构,指的是某个节点指向的后续节点),首先遍历hmap中所有入度为0的节点,说明这些课程不需要先修课,他们可以直接被修完。将这些节点去掉,并且将该节点的后续节点的hmap值-1。再次遍历hmap,去掉入度数为0的节点....用什么结构来实现这个过程呢?队列~

代码:

C++:
class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        //广度优先搜索---记录入度
        unordered_map<int,int> hmap;
        unordered_map<int,vector<int>> record; //记录该门课程的后续课程
        int cnt=0;
        //初始化hmap,record
        for(int i=0;i<numCourses;i++){
            hmap[i]=0;
        }
        int len=prerequisites.size();
        for(int i=0;i<len;i++){
            int a=prerequisites[i][0];
            int b=prerequisites[i][1];
            hmap[a]+=1;
            record[b].push_back(a);
        }

        //将
        deque<int> q;
        //初始化q
        unordered_map<int,int>::iterator iter=hmap.begin();

        for(auto iter:hmap){
            if(iter.second==0){
                q.push_back(iter.first);
                hmap[iter.first]=-1;
            }
        }
        //
        while(!q.empty()){
            int p=q.front();  //该点入度为0,可删除
            q.pop_front();
            cnt++;
            int len=record[p].size();
            for(int i=0;i<len;i++){
                hmap[record[p][i]]--;
            }
            for(auto iter:hmap){
                if(iter.second==0){
                    q.push_back(iter.first);
                    hmap[iter.first]=-1;
                }
            }
        }
        if(cnt==numCourses){
            return true;
        }
        else{
            return false;
        }
    }
};

注意这句代码:

unordered_map<int,int>::iterator iter=hmap.begin();
Python:
class Solution:
    def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
        hmap=[0]*numCourses
        len_pre=len(prerequisites)
        record=[[] for i in range(numCourses)]
        cnt=0

        for i in range(len_pre):
            a=prerequisites[i][0]
            b=prerequisites[i][1]
            hmap[a]+=1
            record[b].append(a)
        
        q=deque()
        for index,value in enumerate(hmap):
            if value==0:
                q.append(index)
                hmap[index]=-1
        
        while q:
            p=q[0]
            q.popleft()
            cnt+=1
            len_=len(record[p])
            for i in range(len_):
                hmap[record[p][i]]-=1
            for index,value in enumerate(hmap):
                if value==0:
                    q.append(index)
                    hmap[index]=-1
        if cnt==numCourses:
            return True
        else:
            return False

Python中的deque需要 from collections import deque

注意这句代码:(替代vector<vector<int>>)

record=[[] for i in range(numCourses)] #正确
record=[[]]* numCourses  #错误

注意这句代码:(替代key为索引的字典/替代需要查找索引的list)

for index,value in enumerate(hmap):

dfs思路:

我们利用hmap来记录节点 i 的邻接节点,利用flag来记录节点的状态(flag=0代表该点未被dfs,flag=1代表该点正在被路上的节点dfs,flag=-1代表该点已被其他节点dfs)。

大致dfs的思路是这样的(以节点 i 开始),首先判断节点 i 是否被其他节点 dfs(即flag=1),如果成立,则说明暂时无环,返回false。其次判断节点 i 是否属于正在被路上节点dfs,如果成立,则代表有环,返回true。如果该点未被访问,将该点的邻接节点依次遍历,遍历中如果有环,返回true,如果无环,将 i 节点的flag值记为-1。

代码:

C++:
class Solution {
public:

    bool dfs(int i,unordered_map<int,vector<int>>& hmap,vector<int>& flag){
        //以第i个点为起点
        //有环返回true,无环返回false
        if(flag[i]==1){return true;}
        if(flag[i]==-1){return false;}
        flag[i]=1;
        int len=hmap[i].size();
        for(int j=0;j<len;j++){
            if(dfs(hmap[i][j],hmap,flag)){
                return true;
            }
        }
        flag[i]=-1;
        return false;
    }

    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        int len=prerequisites.size();
        unordered_map<int,vector<int>> hmap;
        for(int i=0;i<len;i++){
            hmap[prerequisites[i][1]].push_back(prerequisites[i][0]);
        }
        vector<int> flag(numCourses,0);
        for(int i=0;i<numCourses;i++){
            if(dfs(i,hmap,flag)){
                return false;
            }
        }
        return true;
    }
};

Python:

class Solution:
    def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
        def dfs(i,hmap:List[List[int]],flag:List[int]) -> bool:
            if flag[i]==1:
                return True
            if flag[i]==-1:
                return False
            flag[i]=1
            len_hmap=len(hmap[i])
            for j in range(len_hmap):
                if dfs(hmap[i][j],hmap,flag):
                    return True
            flag[i]=-1
            return False

        len_pre=len(prerequisites)
        hmap=[[]for _ in range(numCourses)]
        for j in range(len_pre):
            hmap[prerequisites[j][1]].append(prerequisites[j][0])
        flag=[0]*numCourses
        for j in range(numCourses):
            if(dfs(j,hmap,flag)):
                return False
        return True


http://www.niftyadmin.cn/n/5425882.html

相关文章

蓝桥杯2023年-砍树(dfs,树上差分)

题目描述 给定一棵由 n 个结点组成的树以及 m 个不重复的无序数对 (a1, b1), (a2, b2), . . . , (am, bm)&#xff0c;其中 ai 互不相同&#xff0c;bi 互不相同&#xff0c;ai ≠ bj(1 ≤ i, j ≤ m)。 小明想知道是否能够选择一条树上的边砍断&#xff0c;使得对于每个 (a…

【强化学习笔记一】初识强化学习(定义、应用、分类、性能指标、小车上山案例及代码)

文章目录 第1章 初识强化学习1.1 强化学习及其关键元素1.2 强化学习的应用1.3 强化学习的分类1.3.1 按任务分类1.3.2 按算法分类 1.4 强化学习算法的性能指标1.5 案例&#xff1a;基于Gym库的智能体/环境接口1.5.1 安装Gym库1.5.2 使用Gym库1.5.3 小车上山1.5.3.1 有限动作空间…

记一次系统的bug,yuvImage.compressToJpeg导致内存泄露

在做人脸识别的时候&#xff0c;发现内存一直增加&#xff0c;但是该释放的资源已经释放&#xff0c;经过跟厂家一起排查&#xff0c;是在compressToJpeg转换的时候导致的 原代码&#xff1a;&#xff1a;YuvImage yuvImage new YuvImage(data, ImageFormat.NV21, size.width…

在dpvs上实现ICMP的源进源出

目录 1. 缘起2. 源码分析3. 让ICMP也走源进源出1. 缘起 在网络通信中,当一个请求报文从源主机到达目标主机,并经过中间路由器或交换机进行转发时,请求报文进入主机A的路径和响应报文离开主机A的路径可能不同。这种情况下,就会出现所谓的三角路径问题。如下图: 具体来说,…

怎样在CSDN赚点零花钱

请教一下各位大佬&#xff0c;看到你们在CSDN很多都几万粉丝以上&#xff0c;能不能分享一下有什么涨粉的经验&#xff0c;还有怎样转化为额外收益……感谢各位提供宝贵的经验&#xff0c;谢谢……

【Linux】linux的常用命令

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;MQ ⛺️稳中求进&#xff0c;晒太阳 (Linux常用命令) finalShell 1. ls命令 作用&#xff1a;显示当前目录下的文件及文件夹 举例&#xff1a;在用户目录&#xff08;root)使用ls可以查…

基于springboot+vue实现校企合作项目管理系统项目【项目源码+论文说明】

基于springboot实现校企合作项目管理系统演示 摘要 这是一个计算机的时代&#xff0c;在计算机应用非常广泛的时代中&#xff0c;用计算机来完成对信息的处理有着非常好的使用效果。特别是针对学校而言亦是如此&#xff0c;通过在学校中的信息化建设&#xff0c;能够很好的提升…

使用Julia及R语言生成正态分布的随机数字并写入CSV文件

在操作之前需要先下载Julia的Distributions包&#xff0c;这个包用于进行相关概率分布的函数调用。 在输入 ] 进入Julia包管理模式后输入&#xff1a; add Distributions 这里我使用我们自己实验室的实测数据 &#xff0c;平均值0.67&#xff0c;方差0.11&#xff0c;数据分…