时间复杂度 空间复杂度 ---java

目录

一. 算法效率

二.时间复杂度 

2.1 时间复杂度的概念

2.2 大O的渐进表示法

2.3常见时间复杂度计算举例  

三. 空间复杂度


一. 算法效率

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

二.时间复杂度 

2.1 时间复杂度的概念

时间复杂度的定义:在计算机科学中, 算法的时间复杂度是一个数学函数 ,它定量描述了该算法的运行时间。一个算法执行所耗费的时间,从理论上说,是不能算出来的,只有你把你的程序放在机器上跑起来,才能知道。但是我们需要每个算法都上机测试吗?是可以都上机测试,但是这很麻烦,所以才有了时间复杂度这个分析方式。一个算法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为算法的时间复杂度。

2.2 大O的渐进表示法

// 请计算一下 func1 基本操作执行了多少次?
void func1 ( int N ){
        int count = 0 ;
        for ( int i = 0 ; i < N ; i ++ ) { //N
                for ( int j = 0 ; j < N ; j ++ ) { //N
                        count ++ ;
                }
        }
        for ( int k = 0 ; k < 2 * N ; k ++ ) { //2*N
                count ++ ;
        }
        int M = 10 ;
        while (( M -- ) > 0 ) { //10
                count ++ ;
        }
        System . out . println ( count );
}

 Func1 执行的基本操作次数 :

使用O的渐进表示法:

1 、用常数 1 取代运行时间中的所有加法常数。
2 、在修改后的运行次数函数中,只保留最高阶项。
3 、如果最高阶项存在且不是 1 ,则去除与这个项目相乘的常数。得到的结果就是大 O 阶。

 使用大O的渐进表示法以后,Func1的时间复杂度为:

通过上面我们会发现大 O 的渐进表示法 去掉了那些对结果影响不大的项 ,简洁明了的表示出了执行次数。

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

最坏情况:任意输入规模的最大运行次数 ( 上界 )
平均情况:任意输入规模的期望运行次数
最好情况:任意输入规模的最小运行次数 ( 下界 )
在实际中一般情况关注的是算法的最坏运行情况,所以数组中搜索数据时间复杂度为 O(N).

2.3常见时间复杂度计算举例  

实例 1
// 计算 func2 的时间复杂度?
void func2 ( int N ) {
        int count = 0 ;
        for ( int k = 0 ; k < 2 * N ; k ++ ) { //2*N
                count ++ ;
        }
        int M = 10 ;
        while (( M -- ) > 0 ) { //10
                count ++ ;
        }
        System . out . println ( count );
}

 基本操作执行了2N+10次,通过推导大O阶方法--->时间复杂度为 O(N)

实例2

// 计算 func3 的时间复杂度?
void func3 ( int N , int M ) {
        int count = 0 ;
        for ( int k = 0 ; k < M ; k ++ ) { //M
                count ++ ;
        }
        for ( int k = 0 ; k < N ; k ++ ) { //N
                count ++ ;
        }
        System . out . println ( count );
}

基本操作执行了M+N次,有两个未知数MN时间复杂度为 O(N+M) 

实例3

// 计算 func4 的时间复杂度?
void func4 ( int N ) {
        int count = 0 ;
        for ( int k = 0 ; k < 100 ; k ++ ) { //100
                count ++ ;
        }
        System . out . println ( count );
}

 基本操作执行了100次,通过推导大O阶方法,时间复杂度为 O(1).

 实例4

// 计算 bubbleSort 的时间复杂度?
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 ]) {
                                Swap ( array , i - 1 , i );
                                sorted = false ;
                        }
                }
                if ( sorted == true ) {
                        break ;
                }
        }
}

 错误思想: 因为是两层循环嵌套, 所以时间复杂度为O(N^2)

时间复杂度的计算是要配合逻辑的

正确解法:

第一层循环: 当end = n时, 里层 i 从1到 n-1, 循环了n-1次

第二层循环: 当end = n-1时, 里层i从1到n-2, 循环了n-2次

第三层循环: 当end = n-2时, 里层i从1到n-3,循环了n-3次

...

第n-2层循环: 当end = 3时, 里层i从1到2,循环了2次

第n-1层循环: 当end = 2时, 里层i从1到1,循环了1次

第n层循环: 当end = 1时, 里层循环不进行

所以共循环了(n-1)+(n-2)+(n-3)+...3+2+1=n*(n-1)/2, 通过推导大O阶方法, 时间复杂度为 O(N^2)

实例5 

// 计算 binarySearch 的时间复杂度?
int binarySearch ( int [] array , int value ) {
        int begin = 0 ;
        int end = array . length - 1 ;
        while ( begin <= end ) {
                int mid = begin + (( end - begin ) / 2 );
                if ( array [ mid ] < value )
                        begin = mid + 1 ;
                else if ( array [ mid ] > value )
                        end = mid - 1 ;
                else
                        return mid ;
        }
        return - 1 ;
}

二分查找法的思路: 共N个数

第一次查找: 砍掉一半,剩下N/2个

第二次查找: 再砍掉一半, 剩下N/2^2个 

第三次查找: 再砍掉一半, 剩下N/2^3个 

...

第X次查找: 再砍掉一半, 剩下N/2^X个 

当只剩下一个数时, 就找到了这个数, 所以N/2^X = 1 , 解得X=log(以2为低的)N

(ps: 在算法分析中表示是底数 2,对数为N,有些地方会写成lgN)

所以, 通过推导大O阶方法, 时间复杂度为 O(lgN).

实例 6
// 计算阶乘递归 factorial 的时间复杂度?
long factorial ( int N ) {
        return N < 2 ? N : factorial ( N - 1 ) * N ;
}

一个一般的递归的时间复杂度计算公式(不是所有递归都适用):

 递归的时间复杂度 = 递归的次数 * 每次递归后执行的次数

上述递归:

递归的次数: 当N<2即N=1时, 结束递归, 每次递归-1, 所以congN开始, 共递归了N次

每次递归后执行的次数:每次递归, 只进行了一次三目运算符的判断, 所以执行的次数=1

所以, N*1=N, 通过推导大O阶方法, 时间复杂度为 O(N).

实例 7
// 计算斐波那契递归 fibonacci 的时间复杂度?
int fibonacci ( int N ) {
return N < 2 ? N : fibonacci ( N - 1 ) + fibonacci ( N - 2 );
}

 还是用上述公式:

 递归的时间复杂度 = 递归的次数 * 每次递归后执行的次数

递归的次数:我们画图理解一下

先以F(5)为例:每个F(x)代表一次递归

我们可以看到, 从最上面到最下面, n从5变成了1,也就是一共有五层

第一层有1个数, 第二层有2个数, 第三层有4个数, 我可以得到规律:

第n层有2^(n-1)个数

所以递归的次数为:1+2+4+...+2^(n-1)=2^n +1

每次递归后执行的次数:每次递归, 只进行了一次三目运算符的判断, 所以执行的次数=1

所以, (2^n +1)*1 = 2^n +1, 通过推导大O 阶方法,  时间复杂度为 O(2^N ).

三. 空间复杂度

空间复杂度是对一个算法在运行过程中 临时占用存储空间大小的量度 。空间复杂度不是程序占用了多少 bytes 的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数。空间复杂度计算规则基本跟时间复杂度类似,也使用 O 渐进表示法
实例 1
// 计算 bubbleSort 的空间复杂度?
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 ]) {
                                Swap ( array , i - 1 , i );
                                sorted = false ;
                        }
                }
                if ( sorted == true ) {
                        break ;
                }
        }
}
使用了常数个额外空间,所以空间复杂度为 O(1)

实例 2
// 计算 fibonacci 的空间复杂度?
int [] fibonacci ( int n ) {
        long [] fibArray = new long [ n + 1 ];
        fibArray [ 0 ] = 0 ;
        fibArray [ 1 ] = 1 ;
        for ( int i = 2 ; i <= n ; i ++ ) {
                fibArray [ i ] = fibArray [ i - 1 ] + fibArray [ i - 2 ];
        }
        return fibArray ;
}
动态开辟了 N 个空间,空间复杂度为 O(N)

实例3

// 计算阶乘递归 Factorial 的空间复杂度?
long factorial ( int N ) {
        return N < 2 ? N : factorial ( N - 1 ) * N ;
}

递归调用了N次,开辟了N个栈帧,每个栈帧使用了常数个空间。空间复杂度为O(N) 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于 Flink CDC 打造企业级实时数据集成方案

本文整理自Flink数据通道的Flink负责人、Flink CDC开源社区的负责人、Apache Flink社区的PMC成员徐榜江在云栖大会开源大数据专场的分享。本篇内容主要分为四部分&#xff1a; CDC 数据实时集成的挑战Flink CDC 核心技术解读基于 Flink CDC 的企业级实时数据集成方案实时数据集…

算法复杂度分析

文章目录 有数据范围反推算法复杂度以及算法内容一般方法递归 有数据范围反推算法复杂度以及算法内容 c一秒可以算 1 0 7 10^7 107~ 1 0 8 10^8 108次 一般方法 看循环 有几层循环就可以初步分析O( n i n^i ni) 双指针算法除外O(n) 递归 公式法 根据公式的形式&#xff0…

痤疮分级实验笔记-ResNet

组织数据集 方式1&#xff1a;根据txt文件分类的数据集组织形式&#xff08;放弃&#xff09; 你可以使用Python来读取txt文件中的训练集图片信息&#xff0c;并将这些图片从原始文件夹复制到目标文件夹中。 当程序无法找到标签对应的图片或者目标文件夹中已经存在同名图片时…

技术细分|推荐系统——推荐系统中的数据去偏方法

本篇的主要脉络同样依据中科大何向南教授、合工大汪萌教授联合在 TKDE 上的一篇综述文章展开&#xff1a;Bias and Debias in Recommender System: A Survey and Future Directions。 下面按照前导文章中介绍的数据偏差 Selection Bias、Conformity Bias、Exposure Bias、Posit…

洛谷P1036 [NOIP2002 普及组] 选数【回溯搜索+素数】

P1036 [NOIP2002 普及组] 选数 前言题目题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 题目分析注意事项 代码后话王婆卖瓜 题目来源 前言 期中考逆天大作业&#xff0c;都快没时间写了。不过还是得抽空写一下题目&#xff0c;今天还是做搜索的题单&#xff0c;一题…

【0基础学Java第十一课】-- 认识异常

11. 认识异常 11.1 异常的概念与体系结构11.1.1 异常的概念11.1.2 异常的体系结构11.1.3 异常的分类 11.2 异常的处理11.2.1 防御式编程11.2.2 异常的抛出 throw11.2.3 异常的捕获异常声明throwstry-catch捕获并处理finally问题&#xff1a;既然 finally 和 try-catch-finally …

运动规划Motion-Planning随笔

online verification技术 实时安全校验技术&#xff1a;留一手 首先计算能否通过刹车这种方式得到一条安全轨迹&#xff0c;&#xff08;让速不让道&#xff09;&#xff0c;当刹车有可能碰撞到行人或其他车辆时&#xff0c;则判断变道是否会产生碰撞。如果能变道&#xff0…

Mapbox中点图层和面图层点击事件重叠,禁止点击穿透方案

使用mapbox的小伙伴们可能都遇到过这个问题,就是当地图上有两个图层,一个面图层一个点图层,二者相重合的时候。假设我们想点击点位弹窗展示一些内容,也想点击面图层的时候弹窗展示一些内容,这时候一个有意思的问题就产生了,就是点击点位弹窗的时候面图层对应的弹窗也会弹…

几款Java源码扫描工具(FindBugs、PMD、SonarQube、Fortify、WebInspect)

说明 有几个常用的Java源码扫描工具可以帮助您进行源代码分析和检查。以下是其中一些工具&#xff1a; FindBugs&#xff1a;FindBugs是一个静态分析工具&#xff0c;用于查找Java代码中的潜在缺陷和错误。它可以检测出空指针引用、资源未关闭、不良的代码实践等问题。FindBu…

项目经理只需要有PMP证书就行?

就目前而言&#xff0c;大部分人对于项目经理的认识还停留在&#xff1a;有项目管理经验&#xff0c;有对应的工作年限&#xff0c;有PMP证书。所以绝大多数人都认为只要报考了PMP项目管理&#xff0c;取得PMP证书&#xff0c;即可加入项目经理的圈子&#xff0c;薪资翻倍。 但…

没有PDF密码,如何解密?

PDF文件有两种密码&#xff0c;一个打开密码、一个限制编辑密码&#xff0c;因为PDF文件设置了密码&#xff0c;那么打开、编辑PDF文件就会受到限制。忘记了PDF密码该如何解密&#xff1f; PDF和office一样&#xff0c;可以对文件进行加密&#xff0c;但是没有提供恢复密码的功…

Linux CentOS+宝塔面板工具结合内网穿透实现网站发布至公网可访问

使用Typecho搭建个人博客网站&#xff0c;并内网穿透实现公网访问 文章目录 使用Typecho搭建个人博客网站&#xff0c;并内网穿透实现公网访问前言1. 安装环境2. 下载Typecho3. 创建站点4. 访问Typecho5. 安装cpolar6. 远程访问Typecho7. 固定远程访问地址8. 配置typecho 前言 …

C++ 简介、基本语法、数据类型、变量、常量

一、C简介&#xff1a; C是一种静态类型的、编译式的、通用的、大小写敏感的、不规则的编程语言。支持过程化编程、面向对象编程和泛型编程。C是C的一个超集&#xff0c;任何合法的C程序都是合法的C程序。 面向对象开发的四大特性&#xff1a; ◆ 封装&#xff08;Encapsulat…

vue项目使用easyplayer播放m3u8直播推流

官网 青犀视频 代码库 / 示例 / demo EasyPlayer 示例效果&#xff1a; 项目背景如图 后端给了m3u8的直播地址 协议是 hls / flv 市面上很多第三方热门播放库都可以完成该多屏播放方式 如Video.js 问题在于 分多屏时 会存在性能问题 并且关闭播放器后 即便删除Dom或调用停…

【Python进阶】近200页md文档14大体系第4篇:Python进程使用详解(图文演示)

本文从14大模块展示了python高级用的应用。分别有Linux命令&#xff0c;多任务编程、网络编程、Http协议和静态Web编程、htmlcss、JavaScript、jQuery、MySql数据库的各种用法、python的闭包和装饰器、mini-web框架、正则表达式等相关文章的详细讲述。 Python全套笔记直接地址…

鸿蒙开发-ArkTS 语言

鸿蒙开发-ArkTS 语言 1. 初识 ArkTS 语言 ArkTS 是 HarmonyOS 优选主力开发语言。ArkTS 是基于 TS(TypeScript)扩展的一门语言&#xff0c;继承了 TS 的所以特性&#xff0c;是TS的超集。 主要是扩展了以下几个方面&#xff1a; 声明式UI描述和自定义组件&#xff1a; ArkTS允…

从裸机启动开始运行一个C++程序(十三)

前序文章请看&#xff1a; 从裸机启动开始运行一个C程序&#xff08;十二&#xff09; 从裸机启动开始运行一个C程序&#xff08;十一&#xff09; 从裸机启动开始运行一个C程序&#xff08;十&#xff09; 从裸机启动开始运行一个C程序&#xff08;九&#xff09; 从裸机启动开…

2. OpenHarmony源码下载

OpenHarmony源码下载(windows, ubuntu) 现在的 OpenHarmony 4.0 源码已经有了&#xff0c;在 https://gitee.com/openharmony 地址中&#xff0c;描述了源码获取的方式。下来先写下 windows 的获取方式&#xff0c;再写 ubuntu 的获取方式。 获取源码前&#xff0c;还需要的准…

咖啡馆管理系统点餐外卖小程序效果如何

咖啡一直是很多人喜欢的饮品&#xff0c;比如有些地区的人非常喜欢&#xff0c;熬夜加班醒脑等&#xff0c;咖啡领域市场规模逐年增加&#xff0c;相应的从业商家也在增加&#xff0c;近些年随着线上生态崛起&#xff0c;传统线下咖啡馆经营痛点显露出来。 通过【雨科】平台搭建…

使用sqlserver备份还原,复制迁移数据库

文章目录 前言一、备份数据库二、还原数据库三、其他 前言 当初学sqlserver复制数据库的时候&#xff0c;老师只教了右键数据库生成sql脚本&#xff0c;没说数据库非常大的时候咋搞啊&#xff0c;分离数据库复制一份后在附加上去太危险了 百度一下备份还原数据库针对小白的资料…