Python算法题集_图论(课程表)

 Python算法题集_课程表

  • 题207:课程表
  • 1. 示例说明
  • 2. 题目解析
    • - 题意分解
    • - 优化思路
    • - 测量工具
  • 3. 代码展开
    • 1) 标准求解【循环+递归+全算】
    • 2) 改进版一【循环+递归+缓存】
    • 3) 改进版二【循环+递归+缓存+反向计算】
    • 4) 改进版三【迭代剥离+计数器检测】
  • 4. 最优算法
  • 5. 相关资源

本文为Python算法题集之一的代码示例

题207:课程表

1. 示例说明

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

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

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

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

示例 1:

输入:numCourses = 2, prerequisites = [[1,0]]
输出:true
解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。

示例 2:

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

提示:

  • 1 <= numCourses <= 2000
  • 0 <= prerequisites.length <= 5000
  • prerequisites[i].length == 2
  • 0 <= ai, bi < numCourses
  • prerequisites[i] 中的所有课程对 互不相同

2. 题目解析

- 题意分解

  1. 本题是计算是否会出现无法学习的课程,这种课程的特点是前置课程出现环路,比如A课程的前置课程B的前置课程为A课程
  2. 本题必须进行课程遍历,每个课程都需要检测是否出现环路
  3. 基本的设计思路是循环+递归,循环遍历课程,递归检测环路

- 优化思路

  1. 通常优化:减少循环层次

  2. 通常优化:增加分支,减少计算集

  3. 通常优化:采用内置算法来提升计算速度

  4. 分析题目特点,分析最优解

    1. 如果一个课程已经检测没有出现环路,则前置课程检测到此课程就不用继续检测下去,减少计算量

    2. 可以研究迭代法实现科目检测


- 测量工具

  • 本地化测试说明:LeetCode网站测试运行时数据波动很大【可把页面视为功能测试】,因此需要本地化测试解决数据波动问题
  • CheckFuncPerf(本地化函数用时和内存占用测试模块)已上传到CSDN,地址:Python算法题集_检测函数用时和内存占用的模块
  • 本题超时测试用例较难生成,已经保存为文本文件,本次测试结果详见章节【最优算法】,测试用例文件包含在【相关资源】中

3. 代码展开

1) 标准求解【循环+递归+全算】

循环遍历课程,递归检测环路,能算尽算,不出所料,功能测试就已超时

页面功能测试,未能通关,超时失败在这里插入图片描述

import CheckFuncPerf as cfpclass Solution:def canFinish_base(self, numCourses, prerequisites):list_graph = [[] for x in range(numCourses)]for a, b in prerequisites:list_graph[a].append(b)def dfs_checkring(visited, pres):if not pres:return Trueresult = Truefor course in pres:if course in visited:return Falseresult &= dfs_checkring(visited + [course], list_graph[course])return resultreturn all(dfs_checkring([i], pres) for i, pres in enumerate(list_graph))print(f'prerequisites count of the Courses = {len(check_prerequisites)}')
result = cfp.getTimeMemoryStr(Solution.canFinish_base, aSolution, 50000, check_prerequisites)
print(result['msg'], '执行结果 = {}'.format(result['result']))# 运行结果
prerequisites count of the Courses = 49999
函数 canFinish_base 的运行时间为 50813.51 ms;内存使用量为 7264.00 KB 执行结果 = True

2) 改进版一【循环+递归+缓存】

循环遍历课程,递归检测环路,缓存已经计算的课程环路结果

页面功能测试,勉强通过,超过11%在这里插入图片描述

import CheckFuncPerf as cfpclass Solution:def canFinish_ext1(self, numCourses: int, prerequisites):list_graph = [[] for x in range(numCourses)]for a, b in prerequisites:list_graph[a].append(b)learned = [0] * numCoursesdef dfs_checkring(visited, pres):if not pres:return Trueresult = Truefor course in pres:if course in visited:return Falseif learned[course] > 0:continuelearned[course] = 1result &= dfs_checkring(visited + [course], list_graph[course])return resultfor iIdx, pres in enumerate(list_graph):if learned[iIdx] > 0:continueresult = dfs_checkring([iIdx], pres)if not result:return Falselearned[iIdx] = 1return Trueprint(f'prerequisites count of the Courses = {len(check_prerequisites)}')
result = cfp.getTimeMemoryStr(Solution.canFinish_base, aSolution, 50000, check_prerequisites)
print(result['msg'], '执行结果 = {}'.format(result['result']))# 运行结果
prerequisites count of the Courses = 49999
函数 canFinish_ext1 的运行时间为 66.02 ms;内存使用量为 6112.00 KB 执行结果 = True

3) 改进版二【循环+递归+缓存+反向计算】

循环遍历课程,递归检测环路,但是检测环路修改为从前置科目开始计算此科目的后置科目是否出现环路

页面功能测试,性能良好,超过88%在这里插入图片描述

import CheckFuncPerf as cfpclass Solution:def canFinish_ext2(self, numCourses, prerequisites):def dfs_checkring(iIdx, list_graph, ringflags):if ringflags[iIdx] == -1:return Trueif ringflags[iIdx] == 1:return Falseringflags[iIdx] = 1for jIdx in list_graph[iIdx]:if not dfs_checkring(jIdx, list_graph, ringflags):return Falseringflags[iIdx] = -1return Truelist_graph = [[] for x in range(numCourses) ]list_flags = [0 for x in range(numCourses)]for a, b in prerequisites:list_graph[b].append(a)for iIdx in range(numCourses):if not dfs_checkring(iIdx, list_graph, list_flags):return Falsereturn Trueprint(f'prerequisites count of the Courses = {len(check_prerequisites)}')
result = cfp.getTimeMemoryStr(Solution.canFinish_ext2, aSolution, 50000, check_prerequisites)
print(result['msg'], '执行结果 = {}'.format(result['result']))# 运行结果
prerequisites count of the Courses = 49999
函数 canFinish_ext2 的运行时间为 80.01 ms;内存使用量为 520.00 KB 执行结果 = True

4) 改进版三【迭代剥离+计数器检测】

特殊的迭代思路

  1. 首先必须存在没有任何前置的科目,否则第一门科目都没有办法学习,直接返回False;由此可建立没有前置科目的队列
  2. 迭代没有前置科目的队列,逐步剥离此科目后置科目的计数器,如果后置科目的前置计数器清零,则作为无前置科目放入队列
  3. 迭代完毕后检测有效科目数量是否达标

页面功能测试,马马虎虎,超过55%在这里插入图片描述

import CheckFuncPerf as cfpclass Solution:def canFinish_ext3(self, numCourses, prerequisites):from collections import deque, defaultdictdeque_graph = defaultdict(list)learned = [0] * numCoursesfor course, visited in prerequisites:deque_graph[visited].append(course)learned[course] += 1queue = deque([x for x in range(numCourses) if learned[x] == 0])processed_courses = 0while queue:visited = queue.popleft()processed_courses += 1for course in deque_graph[visited]:learned[course] -= 1if learned[course] == 0:queue.append(course)return processed_courses >= numCoursesprint(f'prerequisites count of the Courses = {len(check_prerequisites)}')
result = cfp.getTimeMemoryStr(Solution.canFinish_ext3, aSolution, 50000, check_prerequisites)
print(result['msg'], '执行结果 = {}'.format(result['result']))# 运行结果
prerequisites count of the Courses = 49999
函数 canFinish_ext3 的运行时间为 84.02 ms;内存使用量为 584.00 KB 执行结果 = True

4. 最优算法

根据本地日志分析,最优算法为第2种方式【循环+递归+缓存】canFinish_ext1

由于四段代码思路一致,主要是使用的数据结构不同,因此经验推出以下结论:

  1. 在作为队列使用时【先进先出】,deque性能远远高于list
  2. 迭代器循环优于循环中进行异常检测
  3. 下标循环和枚举循环性能基本一致
inumCourses = 50000
aSolution = Solution()
testcase_big = open(r'testcase/hot53_big5W.txt', mode='r', encoding='utf-8').read()
testcase_big = testcase_big.replace('[', '')
tmpItems = testcase_big.split(']')
check_pre = []
for aItem in tmpItems:tmpcurpre = aItem.split(',')if len(tmpcurpre) == 2:check_pre.append([int(tmpcurpre[0]), int(tmpcurpre[1])])
check_prerequisites = check_pre
print(f'prerequisites count of the Courses = {len(check_prerequisites)}')
result = cfp.getTimeMemoryStr(Solution.canFinish_base, aSolution, inumCourses, check_prerequisites)
print(result['msg'], '执行结果 = {}'.format(result['result']))
result = cfp.getTimeMemoryStr(Solution.canFinish_ext1, aSolution, inumCourses, check_prerequisites)
print(result['msg'], '执行结果 = {}'.format(result['result']))
result = cfp.getTimeMemoryStr(Solution.canFinish_ext2, aSolution, inumCourses, check_prerequisites)
print(result['msg'], '执行结果 = {}'.format(result['result']))
result = cfp.getTimeMemoryStr(Solution.canFinish_ext3, aSolution, inumCourses, check_prerequisites)
print(result['msg'], '执行结果 = {}'.format(result['result']))# 算法本地速度实测比较
prerequisites count of the Courses = 49999
函数 canFinish_base 的运行时间为 50813.51 ms;内存使用量为 7264.00 KB 执行结果 = True
函数 canFinish_ext1 的运行时间为 66.02 ms;内存使用量为 6112.00 KB 执行结果 = True
函数 canFinish_ext2 的运行时间为 80.01 ms;内存使用量为 520.00 KB 执行结果 = True
函数 canFinish_ext3 的运行时间为 84.02 ms;内存使用量为 584.00 KB 执行结果 = True

5. 相关资源

本文代码已上传到CSDN,地址:Python算法题源代码_LeetCode(力扣)_课程表

一日练,一日功,一日不练十日空

may the odds be ever in your favor ~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/697695.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring整合Junit4和Junit5

1、整合的好处 好处1&#xff1a;不需要自己创建IOC容器对象了好处2&#xff1a;任何需要的bean都可以在测试类中直接享受自动装配 2、操作 整合junit4 ①加入依赖 <dependency><groupId>junit</groupId><artifactId>junit</artifactId><…

代码随想录算法训练营第二十三天补|669. 修剪二叉搜索树 ● 108.将有序数组转换为二叉搜索树 ● 538.把二叉搜索树转换为累加树

平衡树、二叉树、灵活应用中序遍历&#xff08;值大小有序&#xff09; 669. 修剪二叉搜索树 给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中…

Window部署SkyWalking

SkyWalking mysql的驱动依赖 选择下载版本 v9.4 现在后解压缩目录结构 一、修改config目录文件 application.yml 修改1&#xff1a; selector: ${SW_STORAGE:h2} 修改后&#xff1a; selector: ${SW_STORAGE:mysql} 修改2&#xff1a;使用mysql数据库 mysql: properti…

通俗易懂分析:Vite和Webpack的区别

1、对项目构建的理解 先从浏览器出发&#xff0c; 浏览器是由浏览器内核和JS引擎组成&#xff1b;浏览器内核编译解析html代码和css代码&#xff0c;js引擎编译解析JavaScript代码&#xff1b;所以从本质上&#xff0c;浏览器只能识别运行JavaScript、CSS、HTML代码。 而我们在…

敏捷开发最佳实践:领导力维度实践案例——走动式激励

在本节实践案例中&#xff0c;某财险公司信息技术部高级工程师分享了组织级数字化转型中的优秀敏捷领导力实践&#xff0c;不仅解决了产品上市周期长、响应市场变化慢的难题&#xff0c;还打破了部门墙、提升了客户满意度&#xff0c;该案例将为同类企业在组织层面进行有效敏捷…

Centos7配置静态IP详细步骤

使用Centos虚拟机测试时一到切换网段就头疼&#xff0c;总是会有ping不通网关、同段IP和外网的情况。下面出一个尽可能完整的排查思路和配置静态IP的过程。以下为配置nat模式后&#xff0c;出现以上情况的网络不通的排查思路&#xff0c;并配置win10vm8静态IP和centos7虚机nat模…

vue3路由切换过渡动画实现

<router-view v-slot"{ Component }"><transition name"fade" mode"out-in" appear><keep-alive><component :is"Component" /></keep-alive></transition> </router-view>/* 路由切换动画…

SQL字符集

目标:了解字符集的概念&#xff0c;掌握MySQL数据库存储数据的字符集逻辑以及设置方式 字符集概念 MySQL字符集关系 解决乱码问题 字符集设置原理 1、字符集概念 目标:了解字符集概念&#xff0c;掌握字符集存储和读取的实现原理 概念 字符集:charset或者character set&am…

(十二)【Jmeter】线程(Threads(Users))之setUp 线程组

简述 操作路径如下: 作用:在正式测试开始前执行预加载或预热操作,为测试做准备。配置:设置预加载或预热操作的采样器、循环次数等参数。使用场景:确保在正式测试开始前应用程序已经达到稳定状态,减少测试结果的偏差。优点:提供预加载或预热操作,确保测试的准确性。缺…

Centos开机网卡自启动失败

问题背景 每次都要手动启动在这里插入代码片 解决方案: 关闭 NetworkManager 服务 systemctl disable NetworkManager systemctl stop NetworkManager重启就会发现网卡已经可以自动启动了

2024幻兽帕鲁游戏服务器租用价格表_一年和1个月报价明细

游戏服务器租用多少钱一年&#xff1f;1个月游戏服务器费用多少&#xff1f;阿里云4核16G10M游戏服务器26元1个月、149元半年&#xff0c;腾讯云4核16G游戏服务器32元、312元一年&#xff0c;华为云26元&#xff0c;京东云主机也是26元起&#xff0c;游戏服务器配置从4核16G、4…

代码随想录算法刷题训练营day22

代码随想录算法刷题训练营day22&#xff1a;LeetCode(236)二叉树的最近公共祖先、LeetCode(235) 二叉搜索树的最近公共祖先、LeetCode(701)二叉搜索树中的插入操作、LeetCode(450)删除二叉搜索树中的节点 LeetCode(236)二叉树的最近公共祖先 题目 代码 /*** Definition for…

【鸿蒙 HarmonyOS 4.0】路由router

一、介绍 页面路由指在应用程序中实现不同页面之间的跳转和数据传递。HarmonyOS提供了Router模块&#xff0c;通过不同的url地址&#xff0c;可以方便地进行页面路由&#xff0c;轻松地访问不同的页面。 二、页面跳转 2.1、两种跳转模式&#xff1a; router.pushUrl()&…

vue2与vue3中父子组件传参的区别

本次主要针对vue中父子组件传参所进行讲解 一、vue2和vue3父传子区别 1.vue2的父传子 1).在父组件子标签中自定义一个属性 <sonPage :子组件接收到的类名"传输的数据">子组件</sonPage> 2).在子组件中peops属性中拿到自定属性 props: {子组件接收的…

Stable Diffusion算法、结构全流程概述

Stable Diffusion能力强、功能多、插件广&#xff0c;本文拟概述SD的全流程&#xff0c;方便梳理算法各结构的关系 1、stable diffusion训练用ddpm, 采样用ddim DDPM的推理采样步长和训练时的步长一样&#xff0c;导致采样步数过多&#xff0c;推理时间长。DDIM指出&#xff…

安卓游戏开发之音频技术优劣分析

一、引言 在安卓游戏开发中&#xff0c;音频处理技术扮演着至关重要的角色&#xff0c;它不仅能够增强游戏的沉浸感和玩家体验&#xff0c;还能通过声音效果传达关键的游戏信息。以下将对几种常见的安卓游戏音频处理技术进行优劣分析&#xff0c;并结合应用场景来阐述其特点。 …

docker镜像打包和解压

背景 工作记录 打包镜像 docker save -o 压缩包名称.tar 镜像名称:镜像版本 例如 docker save -o app-web.tar app-web:2.0解压镜像 这里解压上面打包的app-web的压缩包 docker load<压缩包名称.tar docker load<app-web.tar这样解压下来的实际就是app-web:2.0这个镜…

微服务-微服务API网关Spring-clould-gateway实战

1. 需求背景 在微服务架构中&#xff0c;通常一个系统会被拆分为多个微服务&#xff0c;面对这么多微服务客户端应该如何去调用呢&#xff1f; 如果根据每个微服务的地址发起调用&#xff0c;存在如下问题&#xff1a; 1.客户端多次请求不同的微服务&#xff0c;会增加客户端…

Qt 事件

1. 事件 事件是对各种应用程序需要知道的由应用程序内部或者外部产生的事情或者动作的通称。在Qt中使用一个对象来表示一个事件&#xff0c;它继承自QEvent类。 2. 事件和信号 事件与信号并不相同&#xff0c;比如我们使用鼠标点击了一下界面上的按钮&#xff0c;那么就会产生…

node 之 初步认识

思考&#xff1a;为什么JavaScript可以在浏览器中被执行 代执行的js代码——JavaScript解析引擎 不同的浏览器使用不同的JavaScript解析引擎 Chrome 浏览器 》 V8 Firefox浏览器 》OdinMonkey(奥丁猴&#xff09; Safri浏览器 》JSCore IE浏览器 》Chakra(查克拉&#xff09; e…