TimeComplexityAndSpaceComplexity - 时间复杂度和空间复杂度- Java

本文解析了时间复杂度概念,介绍了大O表示法的应用,展示了不同代码片段的时间复杂度计算,并讨论了最坏、平均和最好情况。同时,涉及了Java架构中的关键技术和面试准备内容。
摘要由CSDN通过智能技术生成

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!


 

时间复杂度

====================================================================

时间复杂度的概念


时间复杂度的定义:在计算机科学中,算法的时间复杂度是一个函数,它定量描述了该算法的运行时间。一个

算法执行所耗费的时间,从理论上说,是不能算出来的,只有你把你的程序放在机器上跑起来,才能知道。但

是我们需要每个算法都上机测试吗?是可以都上机测试,但是这很麻烦,且不现实。所以才有了时间复杂度这个分析方

式。一个算法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为算法的时间复

杂度。


大O 的渐进表示法


让我们通过代码,来了解它

当我们看到func1方法时,首先,要找到运行次数最多的语句


public class TimeComplexityAndSpaceComplexity {

public static void func1(int N){

int count = 0;

for (int i = 0; i < N ; i++) {

for (int j = 0; j < N ; j++) {

count++;// 第一个就是 这个 count++;,它执行了多少次?

// 两个for嵌套,两个for循环N次,最外围的for循环,每遍历一个数据,嵌套在内部的for循环,就要循环 N 次。

//即 count++; 语句 被循环执行 N*N 次,

// 小技巧,找执行次数最多的语句,你就看哪里有循环就行了。

}

}

for (int k = 0; k < 2 * N ; k++) {

count++;// 这里的 count++; 被执行了 2*N

}

int M = 10;

while ((M–) > 0) {

count++;// 这里count++; 被执行了 10次

}

System.out.println(count);

}

}

经过我们分析,这句代码在程序中 一共被执行了 F(N) = N^2 + 2N + 10

在座的各位,跟着我思考一个问题:

如果我们的 N 越来越大

比如:

N = 10 F(N) = 10^2 + 20 + 10 == 100 + 30 == 130

N = 100 F(N) = 100^2 + 200 + 10 == 10000 + 210 == 10210

N = 1000 F(N) = 1000^2 + 2000 + 10 == 1000000 + 2010 == 1002010



按照这样想法,后面的 2N + 10,随着N增大,就显得微不足道。


在实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,那么这里 我们使用大O的渐进表示法。


大O符号(Big O notation):是用于描述函数渐进行为的数学符号。


推导大O阶方法:


以func1的时间复杂度为例: F(N) = N^2 + 2N + 10

1、用常数1取代运行时间中的所有加法常数。{F(N)= N^2 +2N +1}

2、在修改后的运行次数函数中,只保留最高阶项。{F(N)=N^2}

3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶

假设 使用完方法 1 和 2,把该做的都做了,还剩 3* N^2,

此时,按照方法3的规则去操作(去掉3*),最终的时间复杂度为 O(N^2),

即分析这个代码的时间复杂度,在使用大O的渐进表示法以后

Func1的时间复杂度为 O(N^2).



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

=============================================================================================================

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


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

平均情况:任意输入规模的期望运行次数(根据代码的情况给出平均时间复杂度)

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

例如:在一个长度为N数组中搜索一个数据x

最好情况:1次找到

最坏情况:N次找到

平均情况:N/2次找到(可以这么理解,在中间的位置找到的。)


&ensp;

在实际中一般情况关注的是算法的最坏运行情况,


举个例子:

假设数组中有N个元素,现在我们要在数组中查找一个元素,最坏的情况,该元素处在数组末尾,

也就是说 需要遍历整个数组元素。

故:数组中搜索数据时间复杂度为O(N)


再来看几个代码案例


案例1

public class TimeComplexityAndSpaceComplexity {

public static void func(int N){

int count = 0;

for (int k = 0; k < 2 * N ; k++) {

count++;// 2*N

}

int M = 10;

while ((M–) > 0) {

count++;// 10

}

System.out.println(count);

}

}

时间复杂度为 F(N) = 2*N + 10.使用大0渐进法来表示时间复杂度为 O(N)


案例 2

public class TimeComplexityAndSpaceComplexity {

public static void func(int N,int M) {

int count = 0;

for (int k = 0; k < M; k++) {

count++;// M

}

for (int k = 0; k < N; k++) {

count++;// N

}

System.out.println(count);

}

}

时间复杂度为 F(N) = N + M.使用大0渐进法来表示时间复杂度为 O(N + M)


&ensp;

案例3

public class TimeComplexityAndSpaceComplexity {

public static void func(int N) {

int count = 0;

for (int k = 0; k < 100; k++) {

count++;// 100

}

System.out.println(count);

}

}

时间复杂度为 F(N) = 100.使用大0渐进法来表示时间复杂度为 O(1)


大家在分析时间复杂度时,一定要结合思想,不能光看代码。



接下来,我们来分析 几个复杂 的 时间复杂度 的 程序


冒泡排序

public class TimeComplexityAndSpaceComplexity {

public void bubbleSort(int[] array) {

for (int end = array.length; end > 0; end–) {// 执行 length 次

boolean sorted = true;// 暂不考虑优化(数组已经是有序的, 也就是说 程序在遍历一次判断一下,就结束了)

// 最好情况:时间复杂度为 O(N)

for (int i = 1; i < end; i++) { //length -1 次

if (array[i -1]> array[i]) {

Swap(array, i - 1, i);

sorted = false;

}

}

if (sorted == true) {

break;

}

}

}

}

时间复杂度是考虑最坏情况(每一个元素都需排序),不考虑优化情况和平均情况:

两个for循环嵌套length * (length - 1) == N(N-1) = N^2 - N == N^2

故 冒泡排序的空间复杂度为 O(N^2)


二分查找

public class TimeComplexityAndSpaceComplexity {

int binarySearch(int[] array, int value) {

int left = 0;

int right = array.length - 1;

while (left <= right) {

int mid = (right + left) / 2;

if (array[mid] < value) {

left = mid + 1;

} else if (array[mid] > value) {

right = mid - 1;

} else {

return mid;

}

}

return -1;

}

} 图1

图1

在这里插入图片描述


递归

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

比如说:我这个递归,递归了N次(N)。每次下去(N) 就是 一个循环,循环是循环了 N 次

那么递归的时间的复杂度 为 N * N^2 = N^3

现在我们来看下面的程序(阶乘)

public class TimeComplexityAndSpaceComplexity {

long factorial(int N) {

return N < 2 ? N : factorial(N-1) * N;

}

}

虽然我们不知道该程序的递归次数,但是程序每次递归下去的时候,遇到是三目运算符。

三目运算符 不是循环,所以 每次递归的次数为1次

再来看看 程序,如果我们求的是 4 的阶乘,也就是 N==4,

N<2,那么只有 N==1时,返回 1(终止递归),然后在看后面 factorial(N-1)

每次递归减一,那么 4,3,2,1 一共 4次

也就是说 递归的次数 为 N 次,

所以 时间的复杂度 = 递归的次数 * 每次递归执行的次数 == N * 1 == N

即 O(N)


计算斐波那契递归fibonacci的时间复杂度?

public class TimeComplexityAndSpaceComplexity {

int fibonacci(int N) {

return N < 2 ? N : fibonacci(N-1)+fibonacci(N-2);

}

}

还是一样,每次进来就是一个 三目运算符,每次递归执行的次数为1,

再来看 递归的次数

假设我们想求第四个斐波那契数,那么就需要我们去计算 第3 和 第4 个斐波那契数

因为斐波那契数,从第三位数开始,该数 等于 自身前两个数之和。

那么 第3个斐波那契数 ,需要 第1和第2个斐波那契数

第2个斐波那契数 需要 第1个斐波那契数,(因为N<2,是终止条件)

至于,第1个斐波那契数,就不需要再计算了(终止了)

第4个斐波那契数,需要 第3 和 第2个斐波那契数

第3个斐波那契数需要 第2 和 第1 个斐波那契数,第2个斐波那契数,需要第1个斐波那契数,(因为N<2,是终止条件)

最后

Java架构学习技术内容包含有:Spring,Dubbo,MyBatis, RPC, 源码分析,高并发、高性能、分布式,性能优化,微服务 高级架构开发等等。

还有Java核心知识点+全套架构师学习资料和视频+一线大厂面试宝典+面试简历模板可以领取+阿里美团网易腾讯小米爱奇艺快手哔哩哔哩面试题+Spring源码合集+Java架构实战电子书+2021年最新大厂面试题。
在这里插入图片描述

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!
一个 三目运算符,每次递归执行的次数为1,

再来看 递归的次数

假设我们想求第四个斐波那契数,那么就需要我们去计算 第3 和 第4 个斐波那契数

因为斐波那契数,从第三位数开始,该数 等于 自身前两个数之和。

那么 第3个斐波那契数 ,需要 第1和第2个斐波那契数

第2个斐波那契数 需要 第1个斐波那契数,(因为N<2,是终止条件)

至于,第1个斐波那契数,就不需要再计算了(终止了)

第4个斐波那契数,需要 第3 和 第2个斐波那契数

第3个斐波那契数需要 第2 和 第1 个斐波那契数,第2个斐波那契数,需要第1个斐波那契数,(因为N<2,是终止条件)

最后

Java架构学习技术内容包含有:Spring,Dubbo,MyBatis, RPC, 源码分析,高并发、高性能、分布式,性能优化,微服务 高级架构开发等等。

还有Java核心知识点+全套架构师学习资料和视频+一线大厂面试宝典+面试简历模板可以领取+阿里美团网易腾讯小米爱奇艺快手哔哩哔哩面试题+Spring源码合集+Java架构实战电子书+2021年最新大厂面试题。
[外链图片转存中…(img-p0t2fJ5O-1714769743579)]

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

  • 29
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值