算法的时间复杂度、空间复杂度如何比较?

news2024/10/6 5:59:59

目录

一、时间复杂度BigO

大O的渐进表示法:

例题一:

例题2:

例题3:冒泡排序的时间复杂度

例题4:二分查找的时间复杂度

书写对数的讲究:

例题5:

 实例6:

利用时间复杂度解决编程题

​编辑思路一:

思路二:

源码:

思路三:

回顾位操作符

二、空间复杂度详解

概念:

例题1:冒泡排序的空间复杂度是多少?

例题2:单路递归

例题3

解析:

例题4(硬菜,双路递归)

利用空间复杂度解决编程题

思路一:

代码:

思路二:

代码:

思路三:

代码:


一、时间复杂度BigO

首先我们不能以机器运行算法的时间来评判一个算法的时间复杂度,因为即使是相同的算法在不同机器上(机器的个体差异性)运行时间都可能不尽相同,因此我们采用

大O表示法】——算法的渐进复杂度T(n)=O(f(n))。

就是算执行次数

        首先解读这个公式,f(n)表示代码执行的次数,O表示正比例关系,而T(n)就表示算法的渐进复杂度(就是当一个问题量级增加的时候,算法运行时间增长的一个趋势)。

即找到某条基本语句与问题规模N之间的数学表达式,就是算出了该算法的时间复杂度。 

大O的渐进表示法:

实际中我们计算时间复杂度时,我们其实不一定要计算精确的执行次数,而只需要大概执行次数

大O渐进表示法的规则:

  1. 用常数1取代运行时间中的所有加法常数。
  2. 在修改后的运行次数函数中,只保留最高阶项。
  3. 如果最高阶项存在且不是1,则取出与这个项相乘的常数,使其前面的系数是1,得到的就是大O渐进表达式。
  4. 用最坏的情况去考虑计算时间复杂度 。

例题一:

 我们可以计算出++count语句被执行多少次,从而算出该算法的时间复杂度。

不难计算出这样一个数学函数表达式

例题2:

strchr是一个库函数用来计算某个特定字符在字符串中的位置,实现方法就是循环遍历。

这样时间复杂度一共有三种情况:

1、最幸运,遍历一次就找到

2、最不幸,一直遍历到最后才找到

3、取平均值,遍历到中间才找到

以上三种情况,到底哪种是符合时间复杂度的呢?答案是最坏情况!也就是O(N)

下面是更复杂的一些计算时间复杂度的例题。

一些更复杂的代码,我们不能只看代码去计算时间复杂度,我们要看重代码的思想是什么,底层逻辑

例题3:冒泡排序的时间复杂度

 

 我们首先要计算最坏的情况,那就是数据本来从小到大顺序排列,而要求从大到小排列,所以全部都需要重新排,第一次n-1,第二次n-2,第三次n-3,以此类推直到最后的1,这就是一个等差数列求和,公差是1,计算得出最高次项是N^2,所以最终O(N)=N^2。

那最好的情况是不是O(1)呢?

答案不是,因为如果已经排好序,我们还需要判断是否有序,判断是否有序就需要时间!所以最好的情况就是O(N)

例题4:二分查找的时间复杂度

 二分查找的最坏情况就是我们要查找的数据在边界,查找区间缩放只剩下一个值时,就是最坏。最坏情况下查找了多少次?除了多少次2,就查找了多少次

假设区间个数是N,/2/2/2/2一直除到最后区间只剩下一个值。

书写对数的讲究:

由于对数在文本中不好写,支持一些展示公式编辑器才方便,所以时间复杂度简写成logN,只有log以2为底N的对数才可以简写成logN,其他都要写出来。

暴力搜索O(N)和二分查找O(logN)量级的天差地别

例题5:

计算阶乘递归的时间复杂度

 注意计算递归的时间复杂度主要看函数被调用的次数,然后再看函数内部的时间复杂度

递归算法的时间复杂度是多次调用的累加。

我们发现上述代码的递归函数调用了N+1次,而每次函数的内部都是O(1),所以最终的时间复杂度就是O(N).相当于N+1个1的时间复杂度

 实例6:

 跟上面的代码区别是这是一个双路递归,上面是单路递归

 上图是双路递归的调用次数,不难发现规律是以2^n为数量级进行递增,然后再进行等比数列求和,最终计算出来的数量级就是2^n,所以O(N)=2^N

最终的三角形是右下角缺失一块,但并不影响我们的数量级。

但是2^n的时间复杂度算的非常慢,因为CPU能接受是以亿为单位,但是2^n很快就到达CPU的顶峰了。

所以用递归求解斐波那契数列只有理论上可行

利用时间复杂度解决编程题

思路一:

排序+遍历(下一个数不等于下一个数据+1,这个下一个数就是消失的数字)

时间复杂度:O(logN*N)用快排qsort的前提下

思路二:

用0~N等差数列求和公式计算结果减去数组中的值,结果就是消失的数字

时间复杂度:O(N)

源码:
int main()
{
	int arr[] = { 0,1,3 };
	int sum = 2 * 3;//求和直接用等差数列的公式计算
	for (int i=0;i<3;i++)
	{
		sum -= arr[i];
	}
	printf("%d\n", sum);
	return 0;
}

思路三:

单身狗思路:异或,两个成对出现的数字中,出现了一个单独的数字,用异或去解决

int main()
{
	int arr[] = { 1,3,4 };
	int ret = 0;
	for (int i=1;i<=4;i++)
	{
		ret ^= i;
	}
	for (int i=0;i<3;i++)
	{
		ret ^= arr[i];
	}
	printf("%d\n", ret);
	return 0;
}
回顾位操作符

^——异或操作符——对应的二进制相同返回0,对应的二进制位不同,就返回1,注意两个相同的数字异或结果是0,任何一个数据与0异或结果就是它本身,并且异或操作符满足交换律

&——按位与操作符——只要有0,结果就是0

|——按位或操作符——只要有1,结果就是1

二、空间复杂度详解

概念:

空间复杂度也是一个数学表达式,是对一个算法在运行过程中额外临时占用存储空间大小的量度

空间复杂度不是程序占用了多少字节的空间,而是计算的是变量的个数,也采用大O渐进表示法。

注意:函数运行时所需要的栈空间(存储参数、局部变量、一些寄存器信息等)在编译期间已经确定好了,因此空间复杂度主要通过函数在运行时候显示申请的额外空间来确定。

例题1:冒泡排序的空间复杂度是多少?

首先参数传过来的数组不算入空间复杂度,如果我们是为了让这个数组排序,额外创建了一个数组,这样的数组才算入空间复杂度。

这样计算发现只有end,exchange,i是我们额外创建的变量,所以一共是3个,即空间复杂度是O(1),注意O(1)不代表空间空间复杂度是1个,而是常数个。

例题2:单路递归

不难看出,为了解决题目,代码额外创建了一个数组,所以最后的空间复杂度就是O(N)

例题3

 

解析:

假设有N层递归,每次递归需要调用一次函数,而调用函数需要创立栈帧,每调用一次函数,就需要创建一次栈帧,而创建一次栈帧需要常数个的空间,注意栈帧在函数使用完毕后是会销毁的,但是空间复杂度计算的是最大的空间占用,所以只有当递归结束时才计算整体的栈帧。所以最终的空间复杂度就是O(N)。

例题4(硬菜,双路递归)

 我们首先要明确这样一个原则,时间是累计的,一去不复返,空间是可以重复利用的

创建和销毁函数栈帧的潜规则

我们先明白这样一个道理,当一个函数调用完毕后,第一个函数创建的栈帧的空间就会返回操作系统,接着继续再调用另外一个函数,第二个函数创建后需要的栈帧空间就是上一个函数的空间,是一模一样的!下面的例子为证,a和b的地址是一样的。

有了上面的基础后,我们还要知道双路递归函数的调用顺序,下图为例。

当我们一路递归调用完毕,函数创建的栈帧销毁,接下来另一个新的函数就会继续用这个空间,重复利用,所以最多额外占用N个空间,即空间复杂度是O(N)

利用空间复杂度解决编程题

思路一:

先将最后一个数取出来,然后将数组里前面的元素向右移动一位,这样就算是右旋一次,接着进行循环,一共循环k次。

这样的空间复杂度O(1),时间复杂度O(N^2),因为考虑最差情况,不能是KN,因为K是一个变量,情况有好有坏,算复杂度直接取最差的情况。

代码:
int main()
{
	int arr[] = { 1,2,3,4,5,6,7 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int k = 0;
	scanf("%d", &k);
	for (int i=0;i<k;i++)
	{
		int tmp = arr[sz - 1];
		for (int j=0;j<sz-1;j++)
		{
			arr[sz - 1 - j] = arr[sz - 2 - j];
		}
		arr[0] = tmp;
	}
	for (int i=0;i<sz;i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

思路二:

用空间换时间,再开辟一个数组,直接将数据拷贝到新的数组,然后再整体拷贝到原来的数组

时间复杂度就是O(N),因为我们额外开辟了一个数组空间,所以我们的空间复杂度就是O(N)

代码:
int main()
{
	int arr[] = { 1,2,3,4,5,6,7 };
	int* tmp = (int*)malloc(sizeof(arr) * sizeof(arr[0]));
	if (tmp == NULL)
	{
		perror(malloc);
		exit(-1);
	}
	int k = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	scanf("%d", &k);
	//注意memcpy最后一个参数以字节为单位!
	memcpy(tmp, arr + sz - k % sz, k % sz * sizeof(arr[0]));
	memcpy(tmp + k % sz, arr, (sz - k % sz) * sizeof(arr[0]));
	memcpy(arr, tmp, sz * sizeof(arr[0]));
	for (int i=0;i<sz;i++)
	{
		printf("%d ", arr[i]);
	}
	free(tmp);
	tmp = NULL;
	return 0;
}

思路三:

三步翻转法

空间复杂度是O(1),时间复杂度是O(N),这就是最优解法!

不容易想到,需要积累!

代码:
void reverse(int* left, int* right)
{
	while (left <= right)
	{
		/*int* tmp = left;
		left = right;
		right = tmp;*///将两个地址交换
		int tmp = *left;
		*left = *right;
		*right = tmp;
		left++;
		right--;
	}
}

int main()
{
	int arr[] = { 1,2,3,4,5,6,7 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int k = 0;
	scanf("%d", &k);
	reverse(arr, arr+sz-k-1);
	reverse(arr + sz-k, arr + sz - 1);
	reverse(arr, arr + sz - 1);
	for (int i=0;i<sz;i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

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

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

相关文章

filter(过滤器)

目录 一、过滤器应用场景 二、Filter&#xff1a;过滤器 1. 快速入门 2. 过滤器执行流程 3. 过滤器生命周期方法 4. 过滤器配置详解 5. 过滤器链(配置多个过滤器) 三、监听器 一、过滤器应用场景 过滤器是处于客户端与服务器资源文件之间的一道过滤网&#xff0c;在访问…

基于Python机器学习、深度学习在气象、海洋、水文等技能提升教程

详情点击链接&#xff1a;基于Python机器学习、深度学习技术提升气象、海洋、水文领域实践应用 前言 Python是功能强大、免费、开源&#xff0c;实现面向对象的编程语言&#xff0c;能够在不同操作系统和平台使用&#xff0c;简洁的语法和解释性语言使其成为理想的脚本语言。…

经营简报及考核360表格

文章目录 经营简报效果图代码tableObjectSpanMethod.js 考核360委员会效果图 经营简报效果图不需要合并单元格且有汇总表头的 懒得封装了&#xff0c;所以整体没有封装 经营简报 效果图 代码 <template><el-tableref"tableRef":data"tableData.lengt…

基础实验篇 | CopterSim中回传提示消息实验

基础实验篇|CopterSim中回传提示消息实验 01实验名称及目的 回传提示消息实验&#xff1a;在飞控中&#xff0c;我们时常需要向外发布一些文字消息&#xff0c;来反映系统当前的运行状态&#xff0c;这个功能可以通过发送“mavlink_log”的uORB消息来实现。 02实验效果 在Cop…

如何让 ChatGPT 更懂你?新功能 Custom Instructions 尝试

对比 我们先来做一个对比实验。这里咱们让 ChatGPT 执行一个很简单的任务 —— 介绍一下 AI 生成内容&#xff08;AIGC&#xff09;。为了能够让 ChatGPT 查询资料&#xff0c;咱们给它提供了 Web Pilot 插件。但是 ChatGPT 并没有主动调用插件&#xff0c;而是直接给出了解释。…

Cisco IOS操作(红茶三杯CCNA)

Cisco IOS模式 &#xff1a;用户模式 #&#xff1a;特权模式(config)#&#xff1a;全局配置模式 接口模式&#xff1a;(config-if)#线路模式&#xff1a;(config-line)#路由配置模式&#xff1a;(config-router)# 使用CLI的帮助 - 命令提示及补全:?、Tab、命令关键字&…

【微信支付】Java微信支付流程

微信支付 微信支付流程 当我们需要支付一件商品时&#xff0c;首先从前端像后端传来商品ID&#xff0c;后端根据商品ID查询商品信息&#xff0c;然后封装订单信息&#xff0c;保存订单。下一步就是向微信远程调用支付接口&#xff0c;微信返回code_url&#xff0c;后端封装co…

vscode恢复被误删的文件(巧用本地历史记录)

背景&#xff1a;&#xff08;希望永远不要有这个背景&#xff09;使用vscode开发项目时&#xff0c;新建了文件&#xff0c;且文件没有git add、没有git stash、没有git commit。但是不小心点中了撤销更改&#xff08;新文件的撤销更改&#xff0c;其实就是删除该新文件&#…

【教学类-34-06】20230726拼图(“三角”凹凸拼图)3*4格子(中班主题《个别化拼图》偏美术)

图片展示&#xff1a; 圆形凹凸角变成三角形凹凸角&#xff0c;便于幼儿剪直线。 背景需求&#xff1a; 5月底&#xff0c;我自制凹凸角拼图&#xff08;动画片图片转拼图&#xff09;给幼儿裁剪&#xff0c;拼贴 教学实际操作时&#xff0c;发现圆形的凸角不适合幼儿裁剪&…

ROS 2 — 托管(生命周期)节点简介

一、说明 这篇文章是关于理解ROS 2中托管&#xff08;生命周期&#xff09;节点的概念。我们描述了概念性的想法以及我们为什么需要它。所以让我们开始吧&#xff01; 二、托管式节点 — 什么和为什么&#xff1f; 为了理解托管式节点&#xff0c;让我们从一个简单的问题陈述开…

微服务——服务异步通讯RabbitMQ

前置文章 消息队列——RabbitMQ基本概念容器化部署和简单工作模式程序_北岭山脚鼠鼠的博客-CSDN博客 消息队列——rabbitmq的不同工作模式_北岭山脚鼠鼠的博客-CSDN博客 消息队列——spring和springboot整合rabbitmq_北岭山脚鼠鼠的博客-CSDN博客 目录 Work queues 工作队列…

数据结构(c++实现)

数据结构 目录 数据结构1.链表实现单链表双链表 2.栈(先进后出&#xff0c;后进先出)3.单调栈4.队列&#xff08;先进先出&#xff09;5.单调队列6.小根堆操作 7.KMP8.Trie树(字典树) 1.链表实现 单链表 #include <iostream>using namespace std;const int N 100010;/…

AcWing 3708. 求矩阵的鞍点

输入样例&#xff1a; 3 4 1 2 3 4 1 2 3 4 1 2 3 4输出样例&#xff1a; 1 4 4 2 4 4 3 4 4 #include<bits/stdc.h> using namespace std; const int N1010; int n,m,a[N][N],x[N],y[N],flag1; int main(){scanf("%d%d",&n,&m);for(int i1;i<n;i…

抖音西瓜实时作品监控,一秒更新提醒

抖音西瓜实时作品监控&#xff0c;一秒更新提醒 安装必要的依赖库&#xff1a;使用pip安装aweme库。 pip install aweme 导入所需的库。 import datetime import time import schedule from aweme import API 创建一个函数&#xff0c;用于检查抖音作品是否更新。 def check_u…

端到端的视频编码方法及码率控制算法

文章目录 基于卷积神经网络的的端到端的视频编码方法自编码器 基于端到端学习的图像编码研究及进展变换量化熵编码 面向视频会议场景的 H.266/VVC 码率控制算法研究基于强化学习的视频码率自适应决策研究自适应流媒体传输技术码率自适应算法研究现状强化学习深度强化学习算法介…

mp4视频太大怎么压缩?教你轻松减小视频大小

MP4视频太大怎么办&#xff1f;很多人都会遇到这样的问题&#xff0c;MP4视频往因为画面清晰度高&#xff0c;画面流畅&#xff0c;所以视频文件会比较大&#xff0c;如果你想向朋友或者家人分享这个视频&#xff0c;但是又因为文件太大无法发送&#xff0c;那么怎么办呢&#…

可视化开发工具:让软件应用开发变得更轻松

一、前言 你是否为编程世界的各种挑战感到头痛&#xff1f;想要以更高效、简单的方式开发出专业级的项目&#xff1f; JNPF低代码工具正是你苦心寻找的产品&#xff01;它是一款专为稍微懂一点点编程思想的入门级人员设计的神奇工具&#xff0c;集成了丰富的功能和组件&#xf…

使用 CSS 自定义属性

我们常见的网站日夜间模式的变化&#xff0c;其实用到了 css 自定义属性。 CSS 自定义属性&#xff08;也称为 CSS 变量&#xff09;是一种在 CSS 中预定义和使用的变量。它们提供了一种简洁和灵活的方式来通过多个 CSS 规则共享相同的值&#xff0c;使得样式更易于维护和修改。…

深度剖析APP开发中的UI/UX设计

作为一个 UI/UX设计师&#xff0c;除了要关注 UI/UX设计之外&#xff0c;还要掌握移动开发知识&#xff0c;同时在日常工作中也需要对用户体验有一定的认知&#xff0c;在本次分享中&#xff0c;笔者就针对自己在工作中积累的一些经验来进行一个总结&#xff0c;希望能够帮助到…

暑假学生使用什么牌子台灯好?分享五款学生使用的台灯

临近暑假&#xff0c;是不是开始补课或写暑假作业了呢&#xff1f;是不是还在为选一款学生使用的台灯而发愁&#xff1f;今天小编就来给大家推荐几款台灯供大家参考参考。 那么问题来了&#xff0c;怎么选择合适的护眼台灯&#xff1f; 第一&#xff1a;先考虑个人预算选择适…