Python 算法:感受算法的小小魅力和复杂度的计算

news2024/12/27 7:16:05

一、小小算法的魅力

这是一个很普通的小例子,但是可以让我们领略到算法改进之后的强大魅力。

已知a+b+c = 1000,且a^2+b^2=c^2,求a、b、c的所有自然数解。
这个很简单,就是通过代码分别给a、b、c赋值,然后返回符合a+b+c = 1000a^2+b^2=c^2的解。
这里有两段参考代码如下:
第一段就是按照一般的试错逻辑,分别遍历1~1000赋值给a、b、c,然后通过条件if a + b + c == 1000 and a**2 + b**2 == c**2取出符合的三个值。

# 代码1:
import time
start_time = time.time()
for a in range(1,1001):
    for b in range(1,1001):
        for c in range(1,1001):
            if a + b + c == 1000 and a**2 + b**2 == c**2:
                print('a:%d, b:%d, c:%d'%(a,b,c))
end_time = time.time()
print('程序总用时:%f'%(end_time-start_time))

代码1的执行结果如下图,本次的执行时间是951.8秒。
image.png

再来看看代码2,在代码1的基础上做了一个小改动,只遍历两次1~1000,第三个数通过1000减去前两个数得到,代码如下:

# 代码2:
import time
start_time = time.time()
for a in range(1,1001):
    for b in range(1,1001):
        if a**2 + b**2 == (1000-a-b)**2:
            print('a:%d, b:%d, c:%d'%(a,b,1000-a-b))
end_time = time.time()
print('程序总用时:%f'%(end_time-start_time))

代码2的执行结果如下图,可以看到本次执行该代码只需要1.4秒。
image.png

从上面两段代码的执行结果,我们可以看到二者的时间相差700倍左右!用代码2替换代码1,每次执行少等待16分钟左右,这是一种特别好的体验。

感受到算法的小小魅力之后,接下来简单讲讲算法的复杂度问题。

二、复杂度

复杂度一般分为两种:时间复杂度和空间复杂度。
时间复杂度主要衡量的是一个算法的运行速度,而空间复杂度主要衡量一个算法所需要的额外空间,在计算机发展的早期,计算机的存储容量很小。所以对空间复杂度很是在乎。但是经过计算机行业的迅速发展,计算机的存储容量已经达到了很高的程度,所以我们如今已经不需要再特别关注一个算法的空间复杂度,更多关注其时间复杂度。

2.1 时间复杂度

时间复杂度,也是渐进时间复杂度(asymptotic time complexity),官方的定义如下:
若存在函数f(n),使得当n趋近于无穷大时, T ( n ) / f ( n ) T(n)/f(n) T(n)/f(n) 的极限值为不等于零的常数,则称 f ( n ) f(n) f(n) T ( n ) T(n) T(n)的同数量级函数。记作 T ( n ) = O ( f ( n ) ) T(n)= O(f(n)) T(n)=O(f(n)),称 O ( f ( n ) ) O(f(n)) O(f(n))为算法的渐进时间复杂度,简称时间复杂度。
渐进时间复杂度用大写O来表示,所以也被称为大O表示法。,常见表示方法如 O ( 1 ) O(1) O(1) O ( l o g n ) O(logn) O(logn) O ( n ) O(n) O(n) O ( n l o g n ) O(nlogn) O(nlogn) O ( n 2 ) O(n^2) O(n2) O ( n 3 ) O(n^3) O(n3) O ( 2 n ) O(2^n) O(2n)等。
一般情况下,复杂度越小,则说明你的代码越好,复杂度的大小参考如下:
O ( 1 ) < O ( l o g n ) < O ( n ) < O ( n l o g n ) < O ( n 2 ) < O ( n 3 ) < O ( 2 n ) < O ( n ! ) < O ( n n ) O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)<O(n^3)<O(2^n)<O(n!)<O(n^n) O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)

计算时间复杂度时,理论上需要考虑到所有需要消耗时间的运行操作,比如说遍历一个元素都是长字符串的列表找到相等的字符串,除了考虑遍历字符串的执行时间,还需要考虑字符串的对比(如下例子)。

for i in ['abc','bcd','cde']:
    if i == 'cde':
        print(i)

一般基础代码,不带任何调用其他对象的代码是常数项,有几行就算执行几次;遍历循环则根据序列的长度定义,假设序列长度为n,遍历1次序列则为n,并列遍历2次则为 2 ∗ n 2*n 2n,嵌套遍历2次则为 n 2 n^2 n2

不过,在实际应用过程,一般会简化时间复杂度,更多时候只是是看影响最大的因素。

2.2 时间复杂度的简化

在比较时间复杂度时通常会采用以下几个方法进行简化之后对比复杂度:

  • 复杂度为常数,使用O(1)表示,如 O ( 23 ) O(23) O(23) O ( 9999 ) O(9999) O(9999)
  • 复杂度包含n时,省略系数与常数项, 如: O ( 2 n + 45 ) ⟶ O ( n ) O(2n+45) \longrightarrow O(n) O(2n+45)O(n)
  • 复杂度为对数时,用O(logn)表示,如: l o g 5 n log_5 n log5n l o g 2 n log_2n log2n
  • 忽略低阶,只取高阶,如 O ( 4 n 3 + 6 n 2 + n ) ⟶ O ( n 3 ) O(4n^3+6n^2+n) \longrightarrow O(n^3) O(4n3+6n2+n)O(n3)

如: l o g n + n l o g n logn+nlogn logn+nlogn表示为 O ( n l o g n ) O(nlogn) O(nlogn)

比较时间复杂度的时候,一般会忽略常数项、低阶项、高阶项的系数和log的底数。比如说 O ( 2 n + 1 ) O(2n+1) O(2n+1)简化为O(n) , O ( 2 ∗ n 3 + 5 n 2 + 5 ) O(2*n^3+5n^2+5) O(2n3+5n2+5)简化为 O ( n 3 ) O(n^3) O(n3) O ( l o g 2 n ) O(log_2n) O(log2n)简化为 O ( l o g n ) O(logn) O(logn)。文章开头的两串代码的复杂度则分别是 O ( n 2 ) O(n^2) O(n2) O ( n 3 ) O(n^3) O(n3)

2个问题:
1、为什么忽略常数项、低阶项和系数?

  • 因为大O其实就是数据量级突破一个点且数据量级非常大的情况下所表现出的时间复杂度,这个点常数项、低阶项和系数已经不起决定性作用。

2、为什么O(logn)不区分对数的底数?

  • 因为一个对数可以转化成为一个常数乘以一个其他底的对数,即 l o g 2 16 = l o g 10 16 / l o g 10 2    ⟺    l o g 10 16 = l o g 10 2 ∗ l o g 2 16 log_2 16=log_{10} 16/log_{10} 2 \iff log_{10} 16 = log_{10} 2 * log_2 16 log216=log1016/log102log1016=log102log216(把16看成是n更有助于下面的理解),所以 O ( l o g 2 n ) = l o g 2 10 ∗ O ( l o g 10 n )    ⟺    O ( l o g i n ) = l o g i j ∗ O ( l o g j n ) O \left(log_2n \right)=log_2 10*O \left(log_{10}n \right) \iff O \left(log_i n \right)=log_i j*O \left(log_jn \right) O(log2n)=log210O(log10n)O(login)=logijO(logjn) O ( l o g i n )    ⟹    O ( l o g j n )    ⟹    O ( l o g n ) O \left(log_i n \right) \implies O \left(log_jn \right) \implies O \left(logn \right) O(login)O(logjn)O(logn)

2.3 常见函数的复杂度

常见函数Big-O
[n], indexO(1)
append()O(1)
pop()O(n)
insert()O(n)
delO(n)
iterationO(n)
contain()O(n)
[m,n] sliceO(m)
del sliceO(n)
set sliceO(n+m)
reverseO(n)
concaterateO(m)
sortO(n log n)
multiplyO(n*m)
copyO(n)
get itemsO(1)
set itemsO(1)
del itemsO(1)
contains(n)O(1)
iterationO(n)

三、小结

1、一般地,在比较时间复杂度时会采用以下几个方法进行简化再对比:

  • 复杂度为常数,使用O(1)表示,如 O ( 23 ) O(23) O(23) O ( 9999 ) O(9999) O(9999)
  • 复杂度包含n时,省略系数与常数项, 如: O ( 2 n + 45 ) ⟶ O ( n ) O(2n+45) \longrightarrow O(n) O(2n+45)O(n)
  • 复杂度为对数时,用O(logn)表示,如: l o g 5 n log_5 n log5n l o g 2 n log_2n log2n
  • 忽略低阶,只取高阶,如 O ( 4 n 3 + 6 n 2 + n ) ⟶ O ( n 3 ) O(4n^3+6n^2+n) \longrightarrow O(n^3) O(4n3+6n2+n)O(n3)

2、复杂度越小,则说明你的代码越好,复杂度的大小参考如下:
O ( 1 ) < O ( l o g n ) < O ( n ) < O ( n l o g n ) < O ( n 2 ) < O ( n 3 ) < O ( 2 n ) < O ( n ! ) < O ( n n ) O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)<O(n^3)<O(2^n)<O(n!)<O(n^n) O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)

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

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

相关文章

Kafka集群环境搭建及基本使用

前提条件 操作系统&#xff1a;CentOS7服务器&#xff1a;3台Java环境&#xff1a;JDK1.8。安装教程参考JDK1.8安装Zookeeper环境 搭建教程参考Zookeeper集群环境搭建及使用Kafka基础知识参考Kafka角色及功能概览 搭建步骤 下载 执行下载命令wget https://archive.apache.o…

使用SpringBoot实现RabbitMQ各个模式

实现了RabbitMQ各个模式&#xff08;simple、topic、direct、fanout及发送方确认和接收方确认&#xff09;的一个demo 源码&#xff1a;https://gitee.com/xunan29/study-rabbitmq-test-project 参考文章&#xff1a; https://blog.csdn.net/K_kzj_K/article/details/10664225…

[ Linux ] Linux信号概述 信号的产生

目录 0.问题引入&#xff1a; 0.1 将进程设置为后台进程 0.2 查看后台进程并将后台进程提至前台 0.3 将前台进程设置为后台进程 1.信号的概念 2.查看信号列表 3.信号处理的常见方式 4.信号的产生 4.1 用户层产生信号的方式 4.1.1通过终端按键产生信号 4.1.2调用系统函…

【数据集研究】PASCAL VOC 2007

目录1、数据集地址2、适用的比赛1&#xff09;Main Competitions2&#xff09;Taster Competitions3、类别及类别的定义1&#xff09;数据集包含的类别2&#xff09;类别的定义4、数据集1&#xff09;训练集、验证集、测试集2&#xff09;图片和待检测物在类别的分布详情5、标注…

Kamiya丨Kamiya艾美捷小鼠BDNF ELISA原理分析

Kamiya艾美捷小鼠BDNF ELISA预期用途&#xff1a; 小鼠BDNF ELISA用于定量测定小鼠细胞培养物上清液、细胞裂解物、细胞培养物中的BDNF&#xff0c; 血清和血浆&#xff08;肝素、EDTA、柠檬酸盐&#xff09;。仅供研究使用。 引言&#xff1a; 脑源性神经营养因子&#xff…

多线程与高并发(13)——Java常见并发容器总结

本文总结常见的并发容器&#xff0c;包含ConcurrentHashMap、CopyOnWriteArrayList 、ConcurrentLinkedQueue、BlockingQueue 、ConcurrentSkipListMap&#xff0c;本文仅做简单的总结&#xff0c;不做详细的源码分析。 一、ConcurrentHashMap HashMap不是线程安全的&#xf…

Linux基本命令(三)——服务器搭建

搭建简单Web服务器 安装web服务 yum -y install httpd 启动httpd服务 systemctl start httpd查看httpd是否开启成功 service httpd status以下是状态信息&#xff1a; 重新启动httpd systemctl restart httpd6.进入主配置文件 vim /etc/httpd/conf/httpd.conf编辑自配置文件 v…

FPGA控制W5500完成UDP环回测试

FPGA控制W5500完成UDP环回测试&#xff11; 前言&#xff12; 前期准备&#xff13; &#xff37;5500寄存器描述4 &#xff37;5500 环回测试4.1 W5500初始化4.1.1 通用寄存器初始化4.1.2 socket寄存器初始化4.2 W5500数据接收4.3 W5500数据发送4.4 数据环回5 总结&#x…

RKMEDIA--VO的使用

这一节主要说说rkmedia vo模块的使用。 rkmedia的vo是对DRM接口的封装&#xff0c;提供给用户更方便的使用&#xff0c;rv1126/rv1109支持两个vo图层。 1、首先先介绍一下DRM的测试命令--modetest&#xff0c;用来确认当前屏幕能够正常点亮。 modetest -M rockchip //打印出…

融云艾瑞发布《政企数智办公平台行业研究报告》,解读数智化时代的办公新趋势

关注公众号文章扫码报名融云&艾瑞“政企数智办公报告及新品发布会” 近期&#xff0c;安全可信的通信云服务商融云&#xff0c;携手业内权威研究机构艾瑞咨询联合发布《2022 年中国政企数智办公平台行业研究报告》&#xff08;下简称《报告》&#xff09;&#xff0c;回顾政…

Kotlin高仿微信-第28篇-朋友圈-预览图片、预览小视频

Kotlin高仿微信-项目实践58篇详细讲解了各个功能点&#xff0c;包括&#xff1a;注册、登录、主页、单聊(文本、表情、语音、图片、小视频、视频通话、语音通话、红包、转账)、群聊、个人信息、朋友圈、支付服务、扫一扫、搜索好友、添加好友、开通VIP等众多功能。 Kotlin高仿…

ios照片误删怎么恢复,iphone已经删除的照片怎么恢复

苹果手机里面的重要照片被删除了&#xff0c;相信很多人都比较着急&#xff0c;想要想办法找回来。ios照片误删怎么恢复&#xff1f; 方法1.通过“最近删除”恢复照片 苹果删除的照片如何恢复&#xff1f;一般情况下&#xff0c;从苹果手机刚删除的照片会暂存在“最近删除”这…

使用MAT分析线上问题实战

概述 MAT&#xff0c;下载地址&#xff0c;Eclipse Memory Analysis Tools&#xff0c;一个分析Java堆数据的专业工具&#xff0c;可以计算出内存中对象的实例数量、占用空间大小、引用关系等&#xff0c;可得知哪些线程阻止垃圾收集器的回收工作&#xff0c;从而定位内存泄漏…

如何低成本减少企业知识流失?天翎知识文档系统+群晖NAS值得一试

编者按&#xff1a;知识管理可以减少企业知识流失&#xff0c;有效提高企业员工工作水平&#xff0c;增强企业综合竞争力。如何小成本做好企业知识管理呢&#xff1f;天翎知识文档系统群晖NAS值得一试。 关键词&#xff1a;标签分类&#xff0c;权限管理&#xff0c;在线预览&…

Git学习

Git是什么 Github作为最大的代码托管平台&#xff0c;是基于Git开发的 Git是最优秀的版本控制工具 iCode是基于Git的代码托管平台 版本控制&#xff1a;是对软件开发过程中各种程序代码&#xff0c;配置文件&#xff0c;说明文档等。 版本控制系统&#xff1a;集中式、分布式 …

在Mac中管理多版本 java——安装和使用 jenv

jenv 的 github 地址:https://github.com/jenv/jenv 安装 $ brew install jenv安装成功后需要进行一下简单的配置,让它可以起作用 使用Bash的情况$ echo export PATH="$HOME/.jenv/bin:$PATH" >> ~/.bash_profile $ echo eval "$(jenv init -)" &…

MAC 搭建vue开发环境,配置环境变量

1.官网下载nodejs安装包 http://nodejs.p2hp.com/ 下载完成后安装&#xff0c;一直点击下一步即可 2.自定以配置全局模块路径和缓存路径 先自己找一个路径创建两个文件夹&#xff0c;node_cache 和 node_global 打开终端&#xff0c;执行一下俩条命令,注意引号中的路径要换…

图纸识别自动生成BOM清单的方法

01 方案应用领域及行业 高端装备制造业行业、离散型制造业、电气机械和器材制造业等。 02 方案应用场景 某特变电工公司是国内输变电行业的核心骨干企业&#xff0c;每年生产产能巨大&#xff0c;拥有海量的技术图纸&#xff0c;因此技术人员人工拆解设计图纸的工作难度系数大…

【优化调度】基于改进遗传算法的公交车调度排班优化的研究与实现(Matlab代码实现)

目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码 1 概述 本文对当前公交企业调度系统进行了分析&#xff0c;建立了公交排班的数学模型。本文基于数据挖掘分析的结果上&#xff0c;使用截面客流量数据对模型进行约束&#xff0c;得出了公交客流出行的空间分布规律。再以…

软件测试1

这里写自定义目录标题软件测试的定义1、软件测试的目的2、软件测试的要求3、测试与开发的模型3.1 测试的工作流程3.2 开发模型3.2.1 瀑布模型3.2.2 增量模型3.2.3 快速模型3.2.4 其他模型3.3 测试模型4、测试与开发的关系5、软件测试分类软件测试的定义 找Bug,发现缺陷。使用人…