Java-数据结构-时间和空间复杂度

一、什么是时间和空间复杂度?

📚 那么在了解时间复杂度空间复杂度之前,我们先要知道为何有这两者的概念

首先我们要先了解"算法",在之前我们学习过关于"一维前缀和与差分""二维前缀和与差分"这部分知识,而这部分知识就属于基础算法中的"前缀和""差分"的两部分,也就是说它们也是算法

而除了它们以外,其实我们在之前的学习中,大部分的知识也都和算法脱不开干系,例如:"枚举""位运算""冒泡排序""二分查找"等,只不过在当时学习时,我们主要在意的是"如何解题"并没有深究题解的时间效率和空间效率

📕 我们先引入一个小题

有一高度10阶的楼梯,每步只能上一阶或二阶,请问从下往上走,一共能得到多少种走法?

这题大家应该是很熟悉的,通过我们之前学习过的函数递归思想,脑海中的解题思路就会是:

反向思考一下,如果我们距离最后一步到达10阶,就是有两种情况"8->10 或 9->10",而"8->10"就需要我们先走到8阶,相应的"9->10"就需要我们先走到9阶,所以从0阶走到10阶的走法应该等于"0阶到9阶的走法+0阶到8阶的走法"

相应的,之前的7,8,9阶也皆是如此,于是我们便能写出递归函数

public static void main(String[] args) {System.out.println(climbStairs(10));}public static int climbStairs(int num){if(num == 0){return 0;}if(num == 1){return 1;}if(num == 2){return 2;}return climbStairs(num - 1) + climbStairs(num - 2);}

这就是我们之前学习过的"函数递归"了,这样的方法确实能得到答案,但是让我们现在思考一下,这个方法的效率是否够高呢?按照我们这段代码的思路来看,运算过程中实际上是这样的:

随着每多1阶楼梯。我们要计算的步骤就都相应乘以2,并且大部分的数据都是重复的。如果我们输入一个较大的数,那么这种算法的时间损耗是相当大的

所以由此看来,这个方法就不算是一个高效率的算法,而判断算法效率如何,就需要我们所提到的"时间和空间复杂度"了。

时间复杂度和空间复杂度是用来表示一个算法的优劣程度的

二、时间复杂度

① 时间复杂度的概念

📚 时间复杂度的定义

算法的时间复杂度是一个数学函数,它能够大致的表示出一个算法的运行时间,因为一个算法运行所消耗的时间,是不能算出精确值的,只有将代码运行一遍,才能够得出对应精确的时间,但是总不能将所有的算法都测试一遍,这样太麻烦了,于是就有了时间复杂度的分析方法:算法中的基本操作执行次数,就称为算法的时间复杂度。

② 大O渐进表示法

📚 我们先举一个例子,试着求一下这段代码的时间复杂度

public static int fun(int n){int a = 0;for(int i = 0;i < n;i++){a++;}return a;}

这段代码我们可以看出,传入n,其中基本操作执行次数就也是n,故此代码的时间复杂度为O(n)。

📚 那么如果我们在其中掺杂了多端基本操作,使得执行次数的函数变得较为复杂呢

public static int fun(int n){int a = 0;for(int i = 0;i < n;i++){a++;}for(int i = 0;i < n;i++){for(int j = 0;j < n;j++){a++;}}a++;a++;a++;return a;}

这段代码中的基本操作执行次数就就稍微比较多了,我们分别来看:第一段的for循环的基本操作次数为n,而第二段的for循环嵌套的基本操作次数为n^2,第三段的基本操作次数3,所以得到的基本操作次数为n + n^2 + 3而所谓的大O渐进法就是为了简化此等函数式的。

③ 推导大O阶方法

📕 用常数1取代运行时间中的所有加法常数。

📕 在修改后的运行次数函数中,只保留最高阶项。

📕 如果最高阶项存在且不是1,则去除以这个项目相乘的常数。

由于我们并不需要计算精确的执行次数,我们就可以将式子中基本操作次数占比较少的部分省略掉,所以我们该式子的时间复杂度可以简化为O(N^2)

(注:常数阶的时间复杂度是O(1),代表是常数次,不是1次,只要是常数,都用O(1)进行表示)

这里我们就可以引用一下刚刚我们所提出的经典问题"爬楼梯问题"来算一下刚刚我们那个不完美的方法的时间复杂度为多少~

我们仍然看之前的思路图,如果要上n阶楼梯,那么就要算(n-1)阶,(n-2)阶而得到(n-1),就要知道(n-2)阶,(n-3)阶分别的可能次数,所以可以得到此图:

这像是一棵二叉树,高度为N-1,节点个数就接近2的N-1次方,所以时间复杂度近似看成O(2^N)

📚 另外有些算法的时间复杂度存在最好、平均和最坏情况

📕 最坏情况:任意输入规模的最大运行次数(上界)

📕 最好情况:任意输入规模的最小运行次数(下界)

📕 常见的时间复杂度量级

常数阶O(1)
对数阶O(logN)
线性阶O(n)
线性对数阶O(nlogN)
平方阶O(n^2)
立方阶O(n^3)
K次方阶O(n^k)
指数阶O(2^n)

顺便一提,一般情况下我们的电脑的单秒运算量大概为 2e8次 我们在平时刷题时也可以按照这个与时间复杂度结合,就能大致估算运行时间了~

三、空间复杂度

空间复杂度是一个函数,它能够描述一个算法执行所需的额外存储空间,同样用大O渐进法表示,如O(1)、O(n)、O(n^2)等。空间复杂度能够直接影响算法对内存资源的使用

在我们平时刷题,或者算法竞赛中,题目会给出空间限制,通常以MB为单位。计算空间复杂度时,我们估算程序使用的内存,基本单位换算如下:

📕 8 b = 1 B
📕 1 KB = 1024 B
📕 1 MB = 1024 KB
📕 1 GB = 1024 MB

我们要知道,int占用4字节,long占用8字节,double占用8字节等,运算空间复杂度需要我们将代码运行过程中所有字节相加并且转换为MB。

📚 接下来让我们看几段代码练习一下

    public static void main(String[] args) {//1int[] n = new int[10000000];//2long[][] n1 = new long[2000][3000];}

📕 一个大小为 n = 10^7 的int数组,内存消耗为:4e7字节,换算成MB为 4e7/(1024*1024) 约等于38.1MB。

📕 一个大小为 2000 * 3000 的 long 二维数组,内存消耗为:8 * 2000 * 3000字节,换算成MB为(8 * 2000 * 3000) / (1024*1024) 约等于45.78MB。

public static void main(String[] args) {int[] arr = {7,9,4,8,5,6,1,2,3};bubbleSort(arr);System.out.println(Arrays.toString(arr));}public static void bubbleSort(int[] array) {for (int end = array.length; end > 0; end--) {boolean sorted = true;for (int i = 1; i < end; i++) {if (array[i - 1] > array[i]) {int tmp = array[i];array[i] = array[i - 1];array[i - 1] = tmp;sorted = false;}}if (sorted == true) {break;}}}

📕 由于bubbleSort使用的都是常数额外空间,于是空间复杂度为O(1)

    public static void main(String[] args) {System.out.println(fun(10));}public static int fun(int n) {int num = 0;int[] m = new int[n];for(int i = 1;i <= n;i++){num++;}return num;}

📕 第一行创建了int型变量,此为O(1),而后第二行创建一个数组,这个数据占用大小为n,后续的代码中并没有创建新的变量,故不用看。则使用的额外空间式子为1 + n,空间复杂度为O(n)

四、优化爬楼梯问题

📚 那么经过几道题的练习,我们再回过头来看我们最开始举例的"爬楼梯问题"

刚刚使用递归的方式求解"爬楼梯问题",我们得到的对应信息为:

时间复杂度为:O(2^n)

空间复杂度为:O(n)

我们刚刚已经意识到了,O(2^n)的时间复杂度有多么可怕,并且O(n)的空间复杂度也并不是特别优秀,那么我们应该如何对其进行优化呢?

时间复杂度太高的原因是因为我们从上而下的进行分支,而这些分支中又出现了很多的重复项,导致我们的代码会在无用的地方浪费很长时间。而想要对从上而下的分支进行操作并且判断是否重复,是并不容易的,那么我们不妨转换一下思路,我们可以从底向上的,一步一步通过迭代的方式来尝试一下

首先我们先算出从1阶到10阶需要走的步数

我们将其写入表格中:

然后让我们一步一步的观察其中的规律:

1阶2阶与3阶的关系:

2阶3阶与4阶的关系:

3阶4阶与5阶的关系:

我们可以观察到一个现象,在每一次的迭代中,F(N)只与F(N - 1)和F(N - 2)有关,也就是说当我们想求一个状态时,只需要保留之前的两个状态就足够了,之前的数据就可以扔掉不要了。

这就是最最简单的一个动态规划问题~

public static int climbStairs(int num){if(num == 0){return 0;}if(num == 1){return 1;}if(num == 2){return 2;}int a = 1;int b = 2;int temp = 0;for(int i = 3;i <= num;i++){temp = a + b;a = b;b = temp;}return temp;}

一共只用了一次for循环,这段代码的时间复杂度显而易见是O(n),而我们只使用了两或三个变量,则空间复杂度为O(1)~

趁热打铁,既然已经讲了这题了,有兴趣的小伙伴也可以写一下这题~就是一样的道理,只是多了一个(一步迈三阶)的可能~实际上我们只需要多写出一个(n == 3)的情况,以及使temp变成(a + b + c)就可以了~

面试题 08.01. 三步问题 - 力扣(LeetCode)

class Solution {public int waysToStep(int n) {if(n < 1){return 0;}//一阶台阶1种走法if(n == 1){return 1;}//两阶台阶2种走法if(n == 2){return 2;}//三阶台阶4种走法if(n == 3){return 4;}long a = 1;long b = 2;long c = 4;long temp = 0;//F(n) = F(n - 1) + F(n - 2) + F(n - 3);//同理,后续的迭代中F(n)也只与F(n - 1) , F(n - 2) , F(n - 3)相关:for(int i = 4;i <= n;i++){temp = a + b + c;a = b;b = c;c = temp;a = a % 1000000007;b = b % 1000000007;c = c % 1000000007;temp = temp % 1000000007;}return (int)temp;}
}

那么这次关于时间和空间复杂度的知识就为大家分享到这里啦,作者能力有限,如果有什么讲的不够清楚或者有错的地方还请多多在评论区指出,我们下次再见咯~

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

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

相关文章

Cesium 实战 27 - 三维视频融合(视频投影)

Cesium 实战 27 - 三维视频融合(视频投影) 核心代码完整代码在线示例在 Cesium 中有几种展示视频的方式,比如墙体使用视频材质,还有地面多边形使用视频材质,都可以实现视频功能。 但是随着摄像头和无人机的流行,需要视频和场景深度融合,简单的实现方式则不能满足需求。…

U盘格式化工具合集:6个免费的U盘格式化工具

在日常使用中&#xff0c;U盘可能会因为文件系统不兼容、数据损坏或使用需求发生改变而需要进行格式化。一个合适的格式化工具不仅可以清理存储空间&#xff0c;还能解决部分存储问题。本文为大家精选了6款免费的U盘格式化工具&#xff0c;并详细介绍它们的功能、使用方法、优缺…

如何使用AI工具cursor(内置ChatGPT 4o+claude-3.5)

⚠️温馨提示&#xff1a; 禁止商业用途&#xff0c;请支持正版&#xff0c;充值使用&#xff0c;尊重知识产权&#xff01; 免责声明&#xff1a; 1、本教程仅用于学习和研究使用&#xff0c;不得用于商业或非法行为。 2、请遵守Cursor的服务条款以及相关法律法规。 3、本…

Spring Boot的开发工具(DevTools)模块中的热更新特性导致的问题

问题&#xff1a; java.lang.ClassCastException: class cn.best.scholarflow.framework.system.domain.entity.SysUser cannot be cast to class cn.best.scholarflow.framework.system.domain.entity.SysUser (cn.best.scholarflow.framework.system.domain.…

异常与中断(上)

文章目录 一、异常与中断的概念引入与处理流程1.1 生活中的中断1.2 母亲如何处理中断1.3 ARM系统中异常与中断处理流程 二、ARM架构中异常与中断的处理2.1 处理流程2.2 cortex M3/M42.2.1 M3/M4的向量表2.2.2 M3/M4的异常/中断处理流程 2.3 cortex A72.3.1 A7的向量表2.3.2 A7的…

Zabbix 监控平台 添加监控目标主机

Zabbix监控平台是一个企业级开源解决方案&#xff0c;用于分布式系统监视和网络监视。它由Zabbix Server和可选组件Zabbix Agent组成&#xff0c;通过C/S模式&#xff08;客户端-服务器模型&#xff09;采集数据&#xff0c;并通过B/S模式&#xff08;浏览器-服务器模型&#x…

游戏关卡设计的常用模式

游戏关卡分为很多种&#xff0c;但常用的有固定套路&#xff0c;分为若干种类型。 关卡是主角与怪物、敌方战斗的场所&#xff0c;包括装饰物、通道。 单人游戏的关卡较小&#xff0c;偏线性&#xff1b; 联机/MMO的关卡较大&#xff0c;通道多&#xff0c;自由度高&#xf…

【容器化技术 Docker 与微服务部署】详解

容器化技术 Docker 与微服务部署 一、容器化技术概述 &#xff08;一&#xff09;概念 容器化技术是一种操作系统级别的虚拟化方法&#xff0c;它允许将应用程序及其依赖项&#xff08;如运行时环境、系统工具、库等&#xff09;打包成一个独立的、可移植的单元&#xff0c;这…

QT集成IntelRealSense双目摄像头3,3D显示

前两篇文章&#xff0c;介绍了如何继承intel realsense相机和opengl。 这里介绍如何给深度数据和色彩数据一块显示到opengl里面。 首先&#xff0c;需要了解深度数据和彩色数据是如何存储的。先说彩色数据。彩色图像一般都是RGB&#xff0c;也就是每个像素有三个字节&#xf…

Postman[4] 环境设置

作用&#xff1a;不同的环境可以定义不同的参数&#xff0c;在运行请求时可以根据自己的需求选择需要的环境 1.创建Environment 步骤&#xff1a; Environment-> ->命名->添加环境变量 2.使用Environment 步骤&#xff1a;Collection- >右上角选择需要的环境

SpringBoot_第二天

SpringBoot_第二天 学习目标 Mybatis整合&数据访问 使用SpringBoot开发企业项目时&#xff0c;持久层数据访问是前端页面数据展示的基础&#xff0c;SpringBoot支持市面上常见的关系库产品(Oracle,Mysql,SqlServer,DB2等)对应的相关持久层框架&#xff0c;当然除了对于关系…

SparseViT:基于稀疏编码Transformer的非语义中心、参数高效的图像篡改定位

摘要 https://arxiv.org/pdf/2412.14598 非语义特征或语义无关特征&#xff0c;与图像上下文无关但对图像篡改敏感&#xff0c;被认为是图像篡改定位&#xff08;IML&#xff09;的重要证据。由于无法获得人工标签&#xff0c;现有工作依赖于手工方法提取非语义特征。手工非语…

【git】git生成rsa公钥的方法

git生成rsa公钥的方法 一&#xff0c;简介二&#xff0c;操作方法三&#xff0c;总结 一&#xff0c;简介 在工作的过程中&#xff0c;经常需要生成rsa的密钥&#xff0c;然后提供给别人&#xff0c;然后别人给你开通代码下载权限。本文介绍如何在本地生成rsa的密钥供参考。 …

【高项】信息系统项目管理师(二)项目管理概论

一、PMBOK的发展 项目管理知识体系&#xff08;PMBOK&#xff09;是由美国项目管理协会&#xff08;PMI&#xff09;开发的一套描述项目管理专业范围的知识体系&#xff0c;包含了对项目管理所需的知识、技能和工具的描述。 二、项目基本要素 2.1 项目基础 项目是为提供一项…

数据中台与数据治理服务方案[50页PPT]

本文概述了数据中台与数据治理服务方案的核心要点。数据中台作为政务服务数据化的核心&#xff0c;通过整合各部门业务系统数据&#xff0c;进行建模与加工&#xff0c;以新数据驱动政府管理效率提升与政务服务能力增强。数据治理则聚焦于解决整体架构问题&#xff0c;确保数据…

程序员测试日常小工具

作为一名程序员&#xff0c;或者测试人员&#xff0c;日常工作最常用的工具有哪些&#xff0c;截图&#xff0c;截图漂浮&#xff0c;翻译&#xff0c;日期处理&#xff0c;api调用...&#xff0c; 当你拿到一串报文后&#xff0c;想要json转换时&#xff0c;是不是要打…

【MySQL高级】第1-4章

第1章 存储过程 1.1 什么是存储过程&#xff1f; 存储过程可称为过程化SQL语言&#xff0c;是在普通SQL语句的基础上增加了编程语言的特点&#xff0c;把数据操作语句(DML)和查询语句(DQL)组织在过程化代码中&#xff0c;通过逻辑判断、循环等操作实现复杂计算的程序语言。 换…

获取用户详细信息-ThreadLocal优化

Thread全局接口可用&#xff0c;不用再重复编写。所以为了代码的复用&#xff0c;使用Thread。把之前的内容&#xff08;函数的参数和map与username&#xff09;注释掉&#xff0c;换为Thread传过来的内容&#xff08;map与username&#xff09;。 因为Thread需要在拦截器里面…

THUCNews解压/THUCNews数据集解压出问题

省流&#xff1a;使用zip64进行解压&#xff0c;文件数目太多windows默认zip16装不下 我在使用THUCNews中文文本数据集时出现了问题&#xff0c;原数据集解压后应该包含以下两个文件夹: 其中THUCNews文件夹下有以新闻类别命名的子文件。官网下载的是一个1.56GB的zip压缩包 而我…

安卓/system/bin下命令中文说明(AI)

ATFWD-daemon&#xff1a;AT指令转发守护进程&#xff0c;用于将AT指令从应用层转发到调制解调器。 PktRspTest&#xff1a;数据包响应测试工具。 StoreKeybox&#xff1a;存储密钥盒工具&#xff0c;用于安全地存储加密密钥。 WifiLogger_app&#xff1a;WiFi日志记录应用&…