【数据结构】算法的时间复杂度和空间复杂度(下)(附leetcode练习题)

news2024/11/16 17:42:39

☃️个人主页:fighting小泽
🌸作者简介:目前正在学习C语言和数据结构
🌼博客专栏:数据结构
🏵️欢迎关注:评论👊🏻点赞👍🏻留言💪🏻

1. 空间复杂度

空间复杂度也是一个数学表达式,是对一个算法在运行过程中临时占用的额外的存储空间大小的量度 。
空间复杂度不是程序占用了多少bytes的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数。
空间复杂度计算规则基本跟实践复杂度类似,也使用大O渐进表示法。
注意:函数运行时所需要的栈空间(存储参数、局部变量、一些寄存器信息等)在编译期间已经确定好了,因此空间复杂度主要通过函数在运行时候显式申请的额外空间来确定。

1.1 空间复杂度的例子

实例1:

计算BubbleSort的空间复杂度?
void BubbleSort(int* a, int n)
{
  assert(a);
   for (size_t end = n; end > 0; --end)
  {
    int exchange = 0;
    for (size_t i = 1; i < end; ++i)
    {
       if (a[i-1] > a[i])
     {
       Swap(&a[i-1], &a[i]);
       exchange = 1;
     }
    }
    if (exchange == 0)
    break;
 }
}

有的朋友会觉得这个冒泡排序的空间复杂度是 O(N),有的会觉得空间复杂度是 O(1)。为什么会觉得是O(N)呢,因为这里有一个数组,这个数组有N个空间。但是数组的N个空间算不算是冒泡排序的消耗?

其实是不算的,因为这个数组存储N个数据,我们对它进行排序其实是对数组的内容进行处理,它本身就要有,不是因为我们要排序而自己开的空间,在冒泡排序里面创建的end和exchange是常数个,所以它的空间复杂度是O(1).

实例2:

// 计算Fibonacci的空间复杂度?
// 返回斐波那契数列的前n项
long long* Fibonacci(size_t n)
{
 if(n==0)
 return NULL;
 
 long long * fibArray = (long long *)malloc((n+1) * sizeof(long long));
 fibArray[0] = 0;
 fibArray[1] = 1;
 for (int i = 2; i <= n ; ++i)
 {
 fibArray[i] = fibArray[i - 1] + fibArray [i - 2];
 }
 return fibArray;
}

正常的斐波那契数列是三个变量来回倒,它的空间复杂度就是O(1),但是我们这里是malloc了一个数组,这个数组有N+1个空间,所以它的空间复杂度就是经典的O(N)。

实例3:

 计算阶乘递归Fac的空间复杂度?
long long Fac(size_t N)
{
 if(N == 0)
 return 1;
 
 return Fac(N-1)*N;
}

这个时候就涉及到一个栈帧的问题了,每次函数调用会建立一个函数栈帧,相当于建立了N个栈帧,那每个栈帧开辟多少空间呢?
每个栈帧里面其实只有常数个,但是因为创建了N个栈帧,所以它的空间复杂度是O(N)。

在这里插入图片描述
实例4:

计算斐波那契递归Fib的空间复杂度?
long long Fib(size_t N)
{
 if(N < 3)
 return 1;
 
 return Fib(N-1) + Fib(N-2);
}

它的时间复杂度是2 ^ N,可能大多数老铁觉得它的空间复杂度也是
2 ^ N,是一样的。

实际上它不是,它的空间复杂度是不好算的,它的空间复杂度是O(N)。
为什么呢?这时候大家就要看到一个问题,递归调用是咋调的?

斐波那契第N项是不是要调用(N-1)和(N-2)啊,那我问大家它是同时调用(N-1)和(N-2)项吗?不是,它会先调用(N-1),然后调用(N-1)下面的(N-2),然后调用下面的(N-3),会一直往下调用,调用到第2项之后才回来,再调用右边再回去,再调用右边再回去。那就意味着这个栈帧的建立是这样的,最多会建立多少个栈帧呢?是0到N-2个栈帧,就是N-1个栈帧。他会先往深不断不断去走,走了回来的时候栈帧就销毁了,再调用右边的会跟左边的重复用一个栈帧空间,那最多会建立多少层呢?N层。可以认为最多就建立左边的这一列,再调用右边的会跟左边的重复用一个栈帧空间。

这里有一句话送给大家:时间是一去不复返的,空间是可以重复利用的。时间是累计计算的,空间不累计计算。

在这里插入图片描述
这里我们再看一个代码:

void Func1()
{
	int a = 0;
	printf("%p\n", &a);
}
void Func2()
{
	int b = 0;
	printf("%p\n", &b);
}
int main()
{
	Func1();
	Func2();

	return 0;
}

在这里插入图片描述
我们发现,a和b是使用同一块空间的,这时因为函数调用时创立栈帧,函数结束时栈帧也会销毁,但是销毁的这块栈帧空间不是不能使用了,而是归还操作系统了,下一次函数栈帧空间也在这里创建,所以a和b的地址是一样的。同理,刚刚斐波那契数列销毁的空间也会被下一次函数调用所利用。
在这里插入图片描述

2.常见复杂度对比

在这里插入图片描述

在这里插入图片描述

3.leetcode练习题

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。189 . leetcode - 旋转数组
在这里插入图片描述

1. 暴力求解,旋转K次

我们可以用一个 tmp 记录下最后一个元素,然后进行for循环,把每个元素向右移动一位,再把 tmp 传给第一个元素就行了。大家可以自己试一试,不够这样写在力扣过不去,会超时。

2. 三段逆置

这是个聪明人才能想出来的方法,先把前 N-K 个元素逆置,再把后 K 个逆置,再把整体逆置就完成了
在这里插入图片描述

void swap(int* a, int* b) {
    int t = *a;
    *a = *b, *b = t;
}

void reverse(int* nums, int start, int end) {
    while (start < end) {
        swap(&nums[start], &nums[end]);
        start += 1;
        end -= 1;
    }
}

void rotate(int* nums, int numsSize, int k) {
    k %= numsSize;
    reverse(nums, 0, numsSize - 1);
    reverse(nums, 0, k - 1);
    reverse(nums, k, numsSize - 1);
}

3. 空间换时间

我们可以创建一个新数组,把前 N-K 个元素放到后面,把后 K 个元素放到前面

注意:当 K 大于numsSize的时候相当于把数组转过了一遍,但是直接写 K 会越界,访问到后面的元素,所以我们可以令 k = (i+k)%numsSize

void rotate(int* nums, int numsSize, int k) {
    int newArr[numsSize];
        for (int i = 0; i < numsSize; i++)
    {
        newArr[(i+k)%numsSize] = nums[i];
    }
    for (int i = 0; i <numsSize; i++)
    {
        nums[i]=newArr[i];
    }
}

结尾

这些就是我给大家分享的关于算法的复杂度的知识啦,希望我们都能有所收获!
先赞后看,养成习惯!!^ _ ^
码字不易,大家的支持就是我坚持下去的动力,点赞后不要忘了关注我哦!

如有错误,还请您批评改正(。ì _ í。)

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

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

相关文章

【Linux】system V 共享内存

文章目录system V1. 共享内存原理第一阶段原理第二阶段原理2. 直接写代码--编写代码进行原理介绍shmget函数ftok函数key值用法1. 创建key值2. 创建共享内存 获取共享内存3. 将自己和共享内存关联起来4. 将自己和共享内存取消关联5. 删除共享内存用指令删除调用系统调用完整代码…

数据库管理-第六十六期 SQL Domain(20230413)

数据库管理 2023-04-13第六十六期 SQL Domain1 基本介绍2 Domain的表达式和条件3 语法4 语义5 示例总结第六十六期 SQL Domain 上一期一笔带过了部分Oracle 23c的新特性&#xff0c;这一期重点讲一下SQL Domain新特性。 【https://docs.oracle.com/en/database/oracle/oracle-…

【提升效率神器】Python简单批量生成PDF文档(详细做法)

文章目录前言一、准备二、基本使用三、批量生成PDF总结前言 日常办公中&#xff0c;经常会使用PDF文档&#xff0c;难免需要对PDF文档进行编辑&#xff0c;有时候PDF文档中的大部分内容都是一样的&#xff0c;只是发送对象不同。 这种模板套用的场景下&#xff0c;使用Python…

BI 知识大全,值得收藏的干货

01、什么是商业智能BI&#xff1f; 商业智能BI可以实现业务流程和业务数据的规范化、流程化、标准化&#xff0c;打通ERP、OA、CRM等不同业务信息系统&#xff0c;整合归纳企业数据&#xff0c;利用数据可视化满足企业不同人群对数据查询、分析和探索的需求&#xff0c;从而为…

OpenCV实例(三)答题卡识别

OpenCV实例&#xff08;三&#xff09;答题卡识别1.答题卡识别概述2.单道题目的识别2.1基本流程及原理2.2代码实例&#xff1a;作者&#xff1a;Xiou 1.答题卡识别概述 随着信息化的发展&#xff0c;计算机阅卷已经成为一种常规操作。在大型考试中&#xff0c;客观题基本不再…

重整网站。。。。。。。。。

重整网站 写好回复的人 “ xxxxxxxx”通知栏&#xff0c;并且快速跳转到需要的页面。个人页面&#xff0c;记录自己发送的消息与回复的信息。以css 上传的图片防止被拉伸拉坏。 下拉的选择下拉的分页的好处。 评论功能的那一栏中的一个小的评论&#xff0c;如果手机端的话&a…

RabbitMQ 保证消息不丢失的几种手段

文章目录1.RabbitMQ消息丢失的三种情况2.RabbitMQ消息丢失解决方案2.1 针对生产者2.1.1 方案1 &#xff1a;开启RabbitMQ事务2.1.2 方案2&#xff1a;使用confirm机制2.2 Exchange路由到队列失败2.3 RabbitMq自身问题导致的消息丢失问题解决方案2.3.1 消息持久化2.3.2 设置集群…

无废话硬核分享:Linux 基础知识点总结很详细,全的很,吐血奉献

Linux 的学习对于一个程序员的重要性是不言而喻的。前端开发相比后端开发&#xff0c;接触 Linux 机会相对较少&#xff0c;因此往往容易忽视它。但是学好它却是程序员必备修养之一。 Linux 基础 操作系统 操作系统Operating System简称OS&#xff0c;是软件的一部分&#x…

【0基础学爬虫】爬虫基础之数据存储

大数据时代&#xff0c;各行各业对数据采集的需求日益增多&#xff0c;网络爬虫的运用也更为广泛&#xff0c;越来越多的人开始学习网络爬虫这项技术&#xff0c;K哥爬虫此前已经推出不少爬虫进阶、逆向相关文章&#xff0c;为实现从易到难全方位覆盖&#xff0c;特设【0基础学…

物联网时代的网络安全

近年来&#xff0c;物联网 (IoT) 彻底改变了我们的生活和工作方式。从智能家居到自动驾驶汽车&#xff0c;物联网设备在我们的日常生活中变得越来越普遍。 根据 Statista 的一份报告&#xff0c;到 2025 年将有超过 750 亿个物联网 (IoT) 设备投入使用。 然而&#xff0c;这…

c++之STl容器-string

目录 容器的分类 string string的概念 string的初始化 string的遍历 string的一些基本操作 char*类型和string类型互转 字符串的连接 字符串的查找和替换 string的截断和删除 容器的分类 在实际的开发过程中&#xff0c;数据结构本身的重要性不会逊于操作于数据结构的算…

SpringMVC03-文件上传、异常处理、拦截器

SpringMVC03 SpringMVC的文件上传 一 、文件上传的前端必要前提 form 表单的 entcype取值必须是&#xff1a;multipart/form-data。默认值&#xff1a;application/x-www-form-urlencoded&#xff0c;是表单请求正文的类型method 属性取值必须是 post提供一个文件选择域 二…

利用ChatGPT,一分钟制作思维导图

大家好&#xff0c;我是易安&#xff01; 今天我来教你如何使用ChatGPT&#xff0c;一分钟制作出一份思维导图 大纲选题 想到一个课题&#xff0c;然后人工梳理出内容大纲&#xff0c;是个挺费精力的事情。但利用ChatGPT来做这件事. 5秒就可以搞定啦&#xff01; 例如&#xf…

Python安全攻防之第二章Python语言基础

2.3 Python模块的安装与使用python模块的安装pip3 install 模块名称py -3 -m pip install 模块名称python模块的导入与使用&#xff08;1&#xff09;Import模块名称采用“Import模块名称”方式时&#xff0c;需要在对象前面加上模块名称作为前缀&#xff0c;具体形式为“模块名…

Nextcloud去掉URL中的index.php以及强制https(Win10子系统WSL)

一、Nextcloud去掉URL中的index.php 1、启用相关模块 cd /var/www/nextcloud #进入程序目录sudo chmod -R 777 .htaccess #设置.htaccess文件权限可读写sudo a2enmod envaudo a2enmod rewrite #启用rewrite模块2、修改nextcloud配置文件 vim /var/www/nextcloud/config/…

Redis数据备份与恢复

Redis数据备份与恢复 文章目录Redis数据备份与恢复1. Redis备份的方式2. RDB持久化2.1 什么是RDB&#xff1f;2.2 Fork操作2.3 save VS bgsave2.4 关于RDB备份的一些配置项2.5 RDB的备份与恢复2.6 RDB的自动触发2.7 RDB的优势与劣势3. AOF持久化3.1 什么是AOF&#xff1f;3.2 A…

hypothesis testing假设检验

假设检验是什么 比如一家巧克力工厂生产的巧克力每个1g&#xff0c;一个工人说&#xff0c;机器在维修之后生产的巧克力不是1g&#xff0c;为了验证工人说的是否正确&#xff0c;需进行假设检验。 随机挑选50个巧克力&#xff0c;计算平均重量。 H0&#xff1a;每个巧克力1g H…

Seatunnel-2.3.0源码解析

一、概述 SeaTunnel是一个简单易用的数据集成框架&#xff0c;在企业中&#xff0c;由于开发时间或开发部门不通用&#xff0c;往往有多个异构的、运行在不同的软硬件平台上的信息系统同时运行。数据集成是把不同来源、格式、特点性质的数据在逻辑上或物理上有机地集中&#x…

Spring学习笔记(二)【CGLIB浅拷贝BeanCopier的使用和详解】

CGLIB浅拷贝BeanCopier的使用和详解 一、bean拷贝工具 bean拷贝工具类比较 常用的bean拷贝工具类当中&#xff0c;主要有Apache提供的beanUtils、Spring提供的beanUtils、Cglib提供的beanCopier&#xff0c;性能上分析如下表所示&#xff08;该表来自网上的数据&#xff09; …

探索Apache Hudi核心概念 (3) - Compaction

Compaction是MOR表的一项核心机制&#xff0c;Hudi利用Compaction将MOR表产生的Log File合并到新的Base File中。本文我们会通过Notebook介绍并演示Compaction的运行机制&#xff0c;帮助您理解其工作原理和相关配置。 1. 运行 Notebook 本文使用的Notebook是&#xff1a;《A…