时间复杂度和空间复杂度的计算方法

什么是算法

算法的定义是这样的:解题方案的准确而完善的描述,是一系列解决问题的清晰指令。巴拉巴拉的,虽然是一小句但还是不想看(题外话:有时候吧专业名词记下来面试的时候还是挺有用的),其实就是解决一个问题的完整性描述。只不过这个描述就可能是用不同的方式或者说是“语言”了。

算法的效率

既然算法是解决问题的描述,那么就像一千个人眼中有一千个阿姆雷特他大姨夫一样,解决同一个问题的办法也是多种多样的,只是在这过程中我们所使用/消耗的时间或者时间以外的代价(计算机消耗的则为内存了)不一样。为了更快、更好、更强的发扬奥利奥…哦不,提高算法的效率。所以很多时候一个优秀的算法就在于它与其他实现同一个问题的算法相比,在时间或空间(内存)或者时间和空间(内存)上都得到明显的降低。

所以呢,算法的效率主要由以下两个复杂度来评估:

时间复杂度:评估执行程序所需的时间。可以估算出程序对处理器的使用程度。
空间复杂度:评估执行程序所需的存储空间。可以估算出程序对计算机内存的使用程度。

设计算法时,时间复杂度要比空间复杂度更容易出问题,所以一般情况一下我们只对时间复杂度进行研究。一般面试或者工作的时候没有特别说明的话,复杂度就是指时间复杂度。


1.0 空间复杂度
一个程序的空间复杂度是指运行完一个程序所需内存的大小。利用程序的空间复杂度,可以对程序的运行所需要的内存多少有个预先估计。一个程序执行时除了需要存储空间和存储本身所使用的指令、常数、变量和输入数据外,还需要一些对数据进行操作的工作单元和存储一些为现实计算所需信息的辅助空间。程序执行时所需存储空间包括以下两部分。  
(1)固定部分。这部分空间的大小与输入/输出的数据的个数多少、数值无关。主要包括指令空间(即代码空间)、数据空间(常量、简单变量)等所占的空间。这部分属于静态空间。
(2)可变空间,这部分空间的主要包括动态分配的空间,以及递归栈所需的空间等。这部分的空间大小与算法有关。
一个算法所需的存储空间用f(n)表示。S(n)=O(f(n))  其中n为问题的规模,S(n)表示空间复杂度。


2.0 - 时间复杂度

接下来我们还需要知道另一个概念:时间频度。这个时候你可能会说:“不是说好一起学算法吗,这些东东是什么?赠品吗?”。非也非也,这是非卖品。

因为一个算法执行所消耗的时间理论上是不能算出来的,没错正是理论上,so我们任然可以在程序中测试获得。但是我们不可能又没必要对每个算法进行测试,只需要知道大概的哪个算法执行所花费的时间多,哪个花费的时间少就行了。如果一个算法所花费的时间与算法中代码语句执行次数成正比,那么那个算法执行语句越多,它的花费时间也就越多。我们把一个算法中的语句执行次数称为时间频度。通常(ps:很想知道通常是谁)用T(n)表示。

在时间频度T(n)中,n又代表着问题的规模,当n不断变化时,T(n)也会不断地随之变化。为了了解这个变化的规律,时间复杂度这一概念就被引入了。一般情况下算法基础本操作的重复执行次数为问题规模n的某个函数,用也就是时间频度T(n)。如果有某个辅助函数f(n),当趋于无穷大的时候,T(n)/f(n)的极限值是不为零的某个常数,那么f(n)T(n)的同数量级函数,记作T(n)=O(f(n)),被称为算法的渐进时间复杂度,又简称为时间复杂度

2.1 - 大O表示法

用O(n)来体现算法时间复杂度的记法被称作大O表示法

一般我们我们评估一个算法都是直接评估它的最坏的复杂度。

大O表示法O(f(n))中的f(n)的值可以为1、n、logn、n^2 等,所以我们将O(1)、O(n)、O(logn)、O( n^2 )分别称为常数阶、线性阶、对数阶和平方阶。下面我们来看看推导大O阶的方法:

推导大O阶

推导大O阶有一下三种规则:

  1. 用常数1取代运行时间中的所有加法常数
  2. 只保留最高阶项
  3. 去除最高阶的常数

举好多栗子

  • 常数阶
let sum = 0, n = 10; // 语句执行一次 
let sum = (1+n)*n/2; // 语句执行一次 
console.log(`The sum is : ${sum}`) //语句执行一次 

这样的一段代码它的执行次数为 3 ,然后我们套用规则1,则这个算法的时间复杂度为O(1),也就是常数阶。

再例如:如果算法的执行时间不随着问题规模n的增加而增长,即使算法中有上千条语句,其执行时间也不过是一个较大的常数。此类算法的时间复杂度是O(1)。
x=91; y=100;
while(y>0) if(x>100) {x=x-10;y–;} else x++;
解答: T(n)=O(1),
这个程序看起来有点吓人,总共循环运行了1000次,但是我们看到n没有?这段程序的运行是和n无关的,就算它再循环一万年,我们也不管他,只是一个常数阶的函数

  • 线性阶
let i =0; // 语句执行一次 
while (i < n) { // 语句执行n次 console.log(`Current i is ${i}`); //语句执行n次i++; // 语句执行n次
}

这个算法中代码总共执行了 3n + 1次,根据规则 2->3,因此该算法的时间复杂度是O(n)。

  • 对数阶
let number = 1; // 语句执行一次 
while (number < n) { // 语句执行logn次number *= 2; // 语句执行logn次
}

上面的算法中,number每次都放大两倍,我们假设这个循环体执行了m次,那么2^m = nm = logn,所以整段代码执行次数为1 + 2*logn,则f(n) = logn,时间复杂度为O(logn)。

  • 平方阶
for (let i = 0; i < n; i++) { // 语句执行n次 for (let j = 0; j < n; j++) { // 语句执行n^2次 console.log('I am here!'); // 语句执行n^2}
}

上面的嵌套循环中,代码共执行 2*n^2 + n,则f(n) = n^2。所以该算法的时间复杂度为O(n^2 )

例如:当有若干个循环语句时,算法的时间复杂度是由嵌套层数最多的循环语句中最内层语句的频度f(n)决定的。
x=1;
for(i=1;i<=n;i++)
for(j=1;j<=i;j++)
for(k=1;k<=j;k++)
x++;   
该程序段中频度最大的语句是(5),内循环的执行次数虽然与问题规模n没有直接关系,但是却与外层循环的变量取值有关,而最外层循环的次数直接与n有关,因此可以从内层循环向外层分析语句(5)的执行次数: 则该程序段的时间复杂度为T(n)=O(n3/6+低次项)=O(n3)

常见时间复杂度的比较

O(1)<O(logn)<O(n)<O(nlogn)<O(n²)<O(n³)<O(2ⁿ)<O(n!)

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

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

相关文章

Vue中嵌入html页面并相互通信

Vue中嵌入html页面并相互通信 引言&#xff1a;由于最近工作中用到了大量的Iframe去集成一些只能通过原生html、css、js开发的功能接口&#xff0c;因此特意做一下过程记录的笔记。方便交流学习使用。 1. Vue中嵌入Html的方式 1.1 html的页面是单独的一个服务&#xff0c;有…

Java中的URL类根据url获取网络文件快速入门Java中的URL(网络编程)

Java中的URL类 远程连接来实现应用。而且&#xff0c;这个平台现在已经可 以对国际互联网以及URL资源进行访问了。Java的URL类可以让访问网络资源就像是访问你本地的文件夹一样方便快捷。我们通过使用Java的URL类 就可以经由URL完成读取和修改数据的操作。 通过一个URL连接&a…

ByteArrayOutputStream详解

介绍&#xff1a; ByteArrayOutputStream 对byte类型数据进行写入的类 相当于一个中间缓冲层&#xff0c;将类写入到文件等其他outputStream。它是对字节进行操作&#xff0c;属于内存操作流 源码解析&#xff1a; public class ByteArrayOutputStream extends OutputStream…

MySQL如何查询表中重复的数据

一、查询重复记录 例&#xff1a;查询员工表里出现重复姓名的记录 思路&#xff1a; 1、查看重复记录&#xff0c;首先要使用分组函数&#xff08;group by&#xff09;&#xff0c;再用聚合函数中的计数函数count(name)给姓名列计数&#xff0c;且使用group by 后不可使用* …

Java中的Socket的用法——Socket、NioSocket

一、Java Socket的分类 Java中的Socket分为普通的Socket和NioSocket。 二、普通Socket Java中的网络通信时通过Socket实现的&#xff0c;Socket分为ServerSocket和Socket两大类&#xff0c;ServerSocket用于服务器端&#xff0c;可以通过accept方法监听请求&#xff0c;监听…

SpringMVC中Controller为什么能够处理并发访问?Springboot中的定时任务是否会发生阻塞?

文章目录SpringMVC中Controller为什么能够处理并发访问&#xff1f;当多个请求同时访问服务器的时候Controller、Service、DAO是线程安全的吗&#xff1f;关于类中的变量Controller、Service、DAO等类都默认为单例模式Controller、Service、DAO等类中的方法当中的并发问题关于D…

Java进阶 - 易错知识点整理

转载&#xff1a;https://blog.csdn.net/qq_33934427/article/details/125903960 文章目录1、JavaEE2、网络基础3、Mysql4、Spring/SpringMVC&#xff08;IOC装配、AOP增强、常用注解&#xff09;5、Spring Boot/Spring Cloud1&#xff09;SpringBoot部分2&#xff09;SpringCl…

如何在高版本谷歌Chrome浏览器中用VLC播放海康、大华RTSP实时视频?

一、背景 随着互联网基础设施的完善以及4G、5G等技术的大规模商用&#xff0c;在Chrome、Firefox、Edge等浏览器播放RTSP视频流也慢慢成为了信息化系统的行业标准。 早些年还可用VLC播放器在网页中播放RTSP视频流&#xff0c;好景不长&#xff0c;2015年Chrome、Firefox等浏览…

MySQL 视图(详解) navicat如何创建视图

文章目录MySQL 视图&#xff08;详解一&#xff0c;视图概念使用视图的原因二&#xff0c;创建视图&#xff08;1&#xff09;基本语法&#xff08;2&#xff09;创建基于单表的视图【实例 1】【实例 2】&#xff08;3&#xff09;创建基于多表的视图【实例 3】&#xff08;4&a…

使用set集合去除重复元素@EqualsAndHashCode注解

如何使用set集合去重 ​ 我们都知道&#xff0c;set集合是无序的&#xff0c;这样也导致set集合里面的元素是不能重复的&#xff0c;因为这一个特性&#xff0c;所以我们经常用set集合进行去重操作&#xff0c;我们下面以一个简单的例子说明set集合是如何进行去重的。 创建去…

BigDecimal 类的 compareTo() 和 equals()方法

BigDecimal 类的 compareTo() 和 equals()方法 1. compareTo()源码 /*** Compares this BigDecimal with the specified BigDecimal. * Two BigDecimal objects that are equal in value but have * a different scale (like 2.0 and 2.00) are considered equal* by this met…

缺少构造方法:Cause java.sql.SQLDataException Unsupported conversion from LONG to java.sql.Timestamp

今天遇到了一个奇怪的错误&#xff0c;报错如下图所示&#xff1a; org.springframework.dao.DataIntegrityViolationException: Error attempting to get column question_id from result set. Cause: java.sql.SQLDataException: Unsupported conversion from LONG to java…

Collectors.reducing总结Collectors.mapping+Collectors.reducing+TreeSet等等

Collectors.reducing总结 1. 方法签名 一个参数 public static <T> Collector<T, ?, Optional<T>> reducing(BinaryOperator<T> op)参数说明 BinaryOperator op 归集操作函数 输入参数T返回T 测试代码 我们这里实现一个简单的求和功能&#xff0…

vim退出快捷键

退出vim的快捷键 不需要进入命令编辑模式 按住shift zz 保存退出 zq 不保存退出&#xff0c;q表示放弃 之所以按住shift&#xff0c;其实是切换大小写 在命令编辑模式下&#xff1a; :q 不保存退出 :q! 不保存强制退出 :wq 保存退出&#xff0c;w表示写入&#xff0c;…

SpringBoot瘦身打包部署

一、前言 最近做的项目由于引入第三方库导致在运行mvn clean package 打jar时&#xff0c;编译出来的 Jar 包很大&#xff08;服务器多达500MB&#xff09;。 二、瘦身前的Jar包 SpringBoot编译出来的Jar包中&#xff0c;磁盘占用大的&#xff0c;是一些外部依赖库&#xff…

XShell直接拖拽文件到服务器,不使用Xftp等文件上传工具

很多情况下&#xff0c;我们使用 Xshell 工具时&#xff0c;如果遇到文件的上传和下载会不可避免的要用到另外一个工具 Xftp&#xff0c;但是频繁的使用 Xftp 会比较麻烦&#xff0c;那么有没有一种更加直接简单的方法呢&#xff1f; 当我们所需要上传的文件比较小的时候&…

System.getProperty()方法获取系统变量

今天在阅读JDBC的DriverManager类源码时&#xff0c;看到了这么一句代码&#xff1a; System.getProperty(“jdbc.drivers”)&#xff1b;getProperty()这个方法是获取指定键指示的系统属性的&#xff0c;也就是说上面的代码获取的是jdbc.drivers这个属性。我写了个测试测试输…

Spring Boot集成Druid异常discard long time none received connection.

Spring Boot集成Druid异常 在Spring Boot集成Druid项目中&#xff0c;发现错误日志中频繁的出现如下错误信息&#xff1a; discard long time none received connection. , jdbcUrl : jdbc:mysql://******? useSSLfalse&allowPublicKeyRetrievaltrue&useUnicodetrue…

局部变量为什么必须赋值才可以使用

在java内存模型中规定&#xff0c;一个新的变量只能在主存中初始化&#xff0c;不允许在工作内存中直接使用一个未被初始化的变量。 工作内存可以理解为局部变量定义的内存区域&#xff0c;也就是线程的工作内存。所谓局部变量就是线程私有的不共享的空间。 类加载准备阶段 类变…

Java 赋值 “=” 讲解

前言 我们从接触java第一天&#xff0c;就是到 是赋值的意思&#xff0c;把等号右边结果的值&#xff0c;赋给等号左边的变量&#xff0c;那具体是怎样赋值呢&#xff1f;你有了解过吗&#xff1f; 1.0版本 大家都知道&#xff0c;java中有 8大基本类型&#xff0c;对于基本…