算法的时间复杂度与空间复杂度

news2024/11/17 19:52:37

…………………………………………………………请添加图片描述…………………………………………………………
………………………………………………………………………加油………………………………………………………………………….

如何衡量一个算法的好与坏呢?这是本篇的重点内容吗,博主将为你介绍判断算法好坏的方法以及几道经典例题。

  • 【思维导图】
  • 1.算法效率
    • 1.1 如何衡量一个算法的好坏?
    • 1.2 算法的复杂度
  • 2.时间复杂度
    • 2.1 时间复杂度的概念
    • 2.2 大O的渐进表示法
    • 2.3 常见时间复杂度计算案例
      • 案例1:func1
      • 案例2:func2
      • 案例3:func3
      • 案例4:strchr
      • 案例5:BubbleSort
      • 案例6:BinarySearch
      • 案例7:阶乘递归Fac
      • 案例8:斐波那契数列递归Fib
  • 3.空间复杂度
    • 3.1 注意:
    • 3.2 案例1:BubbleSort
    • 3.3 案例2:阶乘递归Fac
  • 4.复杂度练习
    • 4.1 消失的数字
    • 4.2 轮转数组

【思维导图】

请添加图片描述

1.算法效率

1.1 如何衡量一个算法的好坏?

如何衡量一个算法的好坏呢?比如对于以下斐波那契数列:

int fib(int N)
{
  if(N<3)
  return 1;
  else
  return Fib(N-1)+Fib(N-2);
}

斐波那契数列的递归实现方式非常简洁,但简洁一定好吗?那该如何衡量其好与坏呢?

1.2 算法的复杂度

算法在编写成可执行程序后,运行时需要耗费时间资源和空间(内存)资源 。因此衡量一个算法的好坏,一般
是从时间和空间两个维度来衡量的,即时间复杂度和空间复杂度

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

2.时间复杂度

2.1 时间复杂度的概念

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

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

请计算一下Func中++a语句总共执行了多少次
void Func1(int n)
{
int a = 0;
for (int i = 0; i < n ; ++ i)
{
 for (int j = 0; j < n ; ++ j)
 {
 ++a;
 }
}
 
for (int k = 0; k < 2 * n ; ++ k)
{
 ++a;
}
int m = 10;
while (m--)
{
 ++a;
}

我们很容易就能看出来func的执行次数为
Func()=n^2+2*n+10;

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

2.2 大O的渐进表示法

使用大O阶方法规则:

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

大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数。

另外有些算法的时间复杂度存在最好、平均和最坏情况:
最好情况:运行次数最少
平均情况:也就是期望运行次数
最坏情况:运行次数最多的

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

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

案例1:func1

计算Func的时间复杂度?
void func1(int N, int M)
{
 int count = 0;
 for (int k = 0; k < M; ++ k)
 {
 ++count;
 }
 for (int k = 0; k < N ; ++ k)
 {
 ++count;
 }

时间复杂度为O(N+M)

案例2:func2

void func2(int n, int m)
{
	int count = 0;
	int i, j;
	for (i = 0; i < n; i++)
	{
		for (j = 0; j < m; j++)
		{
			count++;
		}
	}
}

时间复杂度为O(n*m)

案例3:func3

void func3()
{

	int count = 0;
	int i, j;
	for (i = 0; i <100; i++)
	{
		count++;
	}
}

时间复杂度为O(1);

案例4:strchr

// 计算strchr的时间复杂度?
strchr查找字符串中的字符
const char * strchr ( const char * str, int character );
取决于要查找的字符,最坏的情况下就是最后一个才查到那时间复杂度就为

时间复杂度就为O(n)

案例5:BubbleSort

void BubbleSort(int* arr, int n)
{
	int i = 0;
	int exchange = 0;

	for (i = 0; i < n - 1; i++)
	{
		int j = 0;
		for (j = i; j < n - i - 1; j++)
		{
			if (arr[i > arr[i + 1]])
			{
				int tmp = arr[i];
				arr[i] = arr[i + 1];
				arr[i + 1] = tmp;
				exchange = 1;
			}
		}
		if (exchange == 0)
			break;
	}
}
最坏的情况就是n个数字是无序的
第一个数字进行冒泡排序需要比较n-1次
第二个数字进行冒泡排序需要比较n-2次
第三个数字进行冒泡排序需要比较n-3次…………
也就是n个数字总需要比n^2-n(n+1)/2==n(n-1)/2次
所以在n^2这个量级

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

案例6:BinarySearch

int begin = 0;
 int end = n-1;
 // [begin, end]:begin和end是左闭右闭区间,因此有=号
 while (begin <= end)
 {
 int mid = begin + ((end-begin)>>1);
 if (a[mid] < x)
 begin = mid+1;
 else if (a[mid] > x)
 end = mid-1;
 else
 return mid;
 }
 return -1;
 二分查找也叫折半查找,每次查找中间的一个
 而最坏的情况就是缩放到就剩一个数字的时候
 设有查找x次,则2^x=n
 所以x=logn;

所以时间复杂度为O(logn)

案例7:阶乘递归Fac

int Fac(int n)
{
	if (n == 1 || n == 0)
		return 1;
	else
		return Fac(n - 1) * n;
}
到n=1或者n=0时,才能知道是多少
所以最坏的情况就是调用n次

时间复杂度为O(n)

案例8:斐波那契数列递归Fib

int Fib(int n)
{
	if (n < 3)
		return 1;
	return Fib(n - 1) + Fib(n - 2);
}
注意Fib(n)返回两个函数Fib(n-1)和fib(n-2)
而fib(n-1)又能返回两个函数fib(n-2)fib(n-3)
也就是一个fib函数能返回调用两个
也就是
fib
fib  fib
fib fib fib fib
…………
…………
fib(1)  fib(2)
所以最后执行的次数是2的n次方。

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

3.空间复杂度

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

空间复杂度不是程序占用了多少bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数
空间复杂度计算规则基本跟时间复杂度类似,也使用大O渐进表示法

3.1 注意:

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

3.2 案例1:BubbleSort

计算BubbleSort的空间复杂度?
void BubbleSort(int* arr, int n)
{
	int i = 0;
	int exchange = 0;

	for (i = 0; i < n - 1; i++)
	{
		int j = 0;
		for (j = i; j < n - i - 1; j++)
		{
			if (arr[i > arr[i + 1]])
			{
				int tmp = arr[i];
				arr[i] = arr[i + 1];
				arr[i + 1] = tmp;
				exchange = 1;
			}
		}
		if (exchange == 0)
			break;
	}
}

答案:使用了常数个额外空间,所以空间复杂度为 O(1)

3.3 案例2:阶乘递归Fac

 计算阶乘递归Fac的空间复杂度?
int Fac(int n)
{
	if (n == 1 || n == 0)
		return 1;
	else
		return Fac(n - 1) * n;
}

答案:递归调用了n次,开辟了n个栈帧,每个栈帧使用了常数个空间,空间复杂度为O(n);

4.复杂度练习

4.1 消失的数字

消失的数字
在这里插入图片描述
方法1:排序+二分查找

方法2:根据异或特点

方法3:利用公式计算

我们就讲解方法2和3
方法2:
我们知道按位异或的特点:相同为0,相异为1
相同的数字异或为0.
所以我们可以将该数组数字全部异或,然后再和0~n数字全部异或,最后得到的结果就是缺的。
因为除了缺的数字,其他数字都是成对出现。

int missingNumber(int* nums, int numsSize){

int ret=0;
int i=0;
for(i=0;i<numsSize;i++)
{
    ret^=nums[i];
}
for(int j=0;j<numsSize+1;j++)
{
    ret^=j;
}
return ret;
}

方法3:
我们可以根据公式计算出缺的数字
我们可以将0~n的数字相加得到一个总数。
再用这个总数减去数组里的数字,最后得到的就是缺少的数字。

int missingNumber(int* nums, int numsSize){
int ret=0;
int i=0;
for(i=0;i<numsSize+1;i++)
{
    ret+=i;
}
int j=0;
for(j=0;j<numsSize;j++)
{
    ret-=nums[j];
}
return ret;
}

4.2 轮转数组

在这里插入图片描述
该题与博主写过的《旋转字符串问题-----左旋字符串》本质是一样的。方法也是一样的。
方法1:分治法
我们不会直接右轮k个数字,但我们会右轮一个数字。
只要给右转一个数字这个操作循环k次就可以了
右转的操作可以分成三步:
第一步将最后一个数字保存下来。
第二步将前面数字整体往后覆盖。
第三步将保存的数字放在第一位。

注意轮转是有周期性的,轮转nusSize个数字又变回来了
所以应该这样写k%=numsSize;

void rotate(int* nums, int numsSize, int k){
    k%=numsSize;
    int j = 0;
	for (j = 0; j < k; j++)
	{
		//第一步将最后一个数字拿走
		int tmp = nums[numsSize - 1];
		//第二步将前面的数字整体往后覆盖
		for (int i = numsSize-1; i>0; i--)
		{
			nums[i] = nums[i-1];
		}
		//第三步将保存的最后的数字放在第一位上
		nums[0] = tmp;
	}
}

方法2:三步逆转法:
第一步先逆转前 n-k个数字
第二步再逆转 n-k到n的数字
第三步逆转整体
不过这里要考虑一个k如果大于numsSize时,该怎么办,我们知道当k=numsSize,数组没有变化,当k=numsSize+1时就等于1
所以k相当于是周期出现的
所以应该这样写k%=numsSize;

void reverse(int* left, int* right)
{
	while (left < right)
	{
		int tmp = *left;
		*left = *right;
		*right = tmp;
		left++;
		right--;
	}
}
void rotate(int* nums, int numsSize, int k){
k%=numsSize;
//先逆转左边
reverse(nums,nums+(numsSize-k)-1);
//再逆转右边
reverse(nums+(numsSize-k),nums+numsSize-1);
//再逆转整体
reverse(nums,nums+numsSize-1);
}

………… …请添加图片描述请添加图片描述请添加图片描述……………

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

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

相关文章

财报解读:硬件支撑思科增长,云平台何时能突围?

北京时间2023年2月16日&#xff0c;美国网络设备老牌巨头思科公布了其2023财年第二季度财报&#xff0c;业绩超预期。 据思科财报显示&#xff0c;其2023财年Q2实现营收136亿美元&#xff0c;分析师预期为134.3亿美元&#xff1b;同时给出大超预期的业绩指引&#xff0c;思科预…

jetson nano(ubuntu)编译Qt creator

文章目录一.apt安装二.源码编译安装1.Qt Creator源码下载2.相关软件安装cmakeninjallvm/clang3.Qt Creator源码编译一.apt安装 sudo apt-get install qtcreatorapt安装的版本只有4的&#xff0c;版本较低&#xff0c;只有qmake进行项目配置&#xff0c;6版本以上可以使用cmake…

7大体系防作弊,牛客放大招了!严肃笔试客户端上线!

如果问起学生对在线笔试的印象&#xff0c;“不公平”和“不服气”占了半壁江山。学生认为很多企业的在线笔试系统并不完善。原因一&#xff0c;不能有效地规避部分学生的作弊行为&#xff1b;原因二&#xff0c;在线考试系统不稳定&#xff0c;bug频出&#xff0c;导致笔试发挥…

CURL error 60: SSL certificate problem: certificate has expired

项目使用guzzleHttp做的一个接口&#xff0c;报错&#xff1a;certificate has expired 因为在linux centos环境与window环境有所不同&#xff0c;在此记录一下解决过程。 目录 报错提示 原因 解决方式 1.去掉guzzlehttp的验证 2.更新CA证书 总结 报错提示 cURL error 60…

RadZen运行和部署,生成业务web应用程序

RadZen运行和部署,生成业务web应用程序 快速简单地生成业务web应用程序&#xff0c;可视化地构建和启动web程序&#xff0c;而我们为您创建新代码。 从信息开始 连接到数据库。Radzen推断您的信息并生成一个功能完备的web应用程序。支持MSSQL REST服务。 微调 添加页面或编辑生…

人工智能、机器学习和深度学习有哪些区别?

人工智能在如今越来越火&#xff0c;诸多词汇时刻萦绕在我们耳边&#xff1a;人工智能、机器学习、深度学习等。不少人对这些高频词汇的含义及其背后的关系总是似懂非懂、一知半解。为了帮助大家更好地理解人工智能&#xff0c;这篇文章用最简单的语言解释了这些词汇的含义&…

tomcat-container 源码分析

说明 本文基于 tomcat 8.5.x 编写。author blog.jellyfishmix.com / JellyfishMIX - githubLICENSE GPL-2.0 tomcat 的 container 容器 tomcat 由 connector 和 container 两部分组成&#xff0c;connector 接收到请求后&#xff0c;先将请求包装为 request&#xff0c;然后…

六、H5新特性

文章目录一、H5的兼容二、H5新增特性2.1 语义化标签2.2 增强表单2.3 音频、视频一、H5的兼容 支持 HTML5的浏览器包括Firefox(火狐浏览器)&#xff0c;IE9及其更高版本&#xff0c;Chrome(谷歌浏览器)&#xff0c;Safari,Opera等&#xff0c;国内的遨游浏览器&#xff0c;以及…

【Kubernetes 企业项目实战】07、最新一代微服务网格 Istio 入门到企业实战(上)

目录 一、Istio 介绍 1.1 什么是 service mesh 1.2 什么是 Istio 1.2.1 服务注册和发现 1.2.2 服务度量 1.2.3 灰度发布 1.3 Istio 核心特性 1.3.1 断路器 1.3.2 超时 1.3.3 重试 1.3.4 多路由规则 二、架构和原理 2.1 Istio 架构 2.1.1 数据平面由一组以 Sideca…

【Spring】手动实现简易AOP和IOC

前言 XML&#xff1a;通过Dom4j对XML进行解析和验证。 IOC&#xff1a;通过获取要创建对象的Class类型、构造函数后&#xff0c;通过反射来实现。 AOP&#xff1a;通过使用JDK动态代理和Cglib动态代理实现。 一、解析XML 1.1、解析bean标签 /*** 解析bean标签* param xmlBean…

前端面试当中CDN会问啥------CDN详细教程来啦

⼀、CDN 1. CDN的概念 CDN&#xff08;Content Delivery Network&#xff0c;内容分发⽹络&#xff09;是指⼀种通过互联⽹互相连接的电脑⽹络系统&#xff0c;利 ⽤最靠近每位⽤户的服务器&#xff0c;更快、更可靠地将⾳乐、图⽚、视频、应⽤程序及其他⽂件发送给⽤户&…

代谢组学资讯,全球爆火的ChatGPT,是如何看待三阴性乳腺癌的?

领导说 今天下午6点前必须发出一篇推文 我表面毫无波澜实则内心风起云涌 那么问题来了 我如何才能在下班前发送推文准时下班呢 我要怎么写才能获得趣粉们的认可呢 全球爆火的ChatGPT&#xff0c;让我的格局一下打开~&#xff0c;它能不能成为我的“得力助手”&#xff1f;…

跳空缺口指标公式,主图显示向上向下跳空缺口

跳空缺口包含两种类型&#xff0c;向上跳空缺口和向下跳空缺口。向上跳空缺口是指当天最低价高于昨天的最高价&#xff0c;K线图出现缺口。向下跳空缺口是指当天最高价低于昨天的最低价&#xff0c;K线图出现缺口。 注意一下&#xff0c;上面的缺口定义与百科上有区别&#xf…

授权验证方式有很多、但AOP最为优雅。

前言 有时候项目中需要对接口进行校验&#xff0c;增加鉴权&#xff0c;确保 API 不被恶意调用。 项目中都是这样 这样&#xff0c;部分需要查询一些信息&#xff0c;下文需要使用 这样的代码很多&#xff0c;重复率太高。看着我蛋疼&#xff0c;对此优化一下。 方案 1 …

剑指offer 7 数组中和为0的三个数

此问题属于nsum问题&#xff0c;题目链接&#xff1a;力扣 要求在数组中找到不重复的三元组&#xff0c;三个数加起来为0&#xff0c;且每个下标只能用一次。而且需要返回所有这样的不重复数组。 1. 排序 双指针 1. 「不重复」的本质是什么&#xff1f;我们保持三重循环的大…

SpringBoot——日志文件

基本概念 日志文件记录了程序的报错信息&#xff0c;执行时间&#xff0c;用户的登录状态&#xff0c;操作时间等等 通过日志&#xff0c;我们可以轻松的找到程序的问题&#xff0c;得到程序的相关信息 springBoot启动时控制台打印的这些&#xff0c;就是程序的日志 创建日志…

Kafka报错:Controller 219 epoch 110 failed to change state for partition

集群里面kafka报错&#xff1a;Controller 219 epoch 110 failed to change state for partition maxwell_atlas-0 from OfflinePartition to OnlinePartitionkafka.common.stateChangeFailedException: Failed to elect leader for partition maxwell_atlas-0 under strategy …

SpringWeb

SpringWeb 概述 springWeb 是 spring 框架的一个模块&#xff0c;springWeb 和 spring 无需通过中间整 合层进行整合。 springWeb 是一个基于 mvc 的 web 框架,方便前后端数据的传输. SpringWeb 拥有控制器&#xff0c;接收外部请求&#xff0c;解析参数传给服务层. SpringM…

盘点界面组件DevExtreme 2023年值得期待的一些新功能!

DevExtreme拥有高性能的HTML5 / JavaScript小部件集合&#xff0c;使您可以利用现代Web开发堆栈&#xff08;包括React&#xff0c;Angular&#xff0c;ASP.NET Core&#xff0c;jQuery&#xff0c;Knockout等&#xff09;构建交互式的Web应用程序&#xff0c;该套件附带功能齐…

一文学会进程控制

目录进程的诞生fork函数fork的本质fork的常规用法fork调用失败的原因进程的死亡进程退出的场景常见的进程退出方法正常终止&#xff08;代码跑完&#xff09;echo $?main函数返回调用exit调用_exitexit和_exit的区别进程等待进程等待的重要性进程等待的函数waitwaitpid进程退出…