时间复杂度空间复杂度 力扣:转轮数组,消失的数字

1. 算法效率

  1. 如何衡量一个算法的好坏?
  2. 一般是从时间和空间的维度来讨论复杂度,但是现在由于计算机行业发展迅速,所以现在并不怎么在乎空间复杂度了
  3. 下面例子中,斐波那契看上去很简洁,但是复杂度未必如此
long long Fib(int N){if(N < 3)return 1;return Fib(N-1) + Fib(N-2);}
  1. 摩尔定律,每两年硬件性能就会翻两倍,但是现在这个结论有些失效了,主要是因为计算机行业现在快处于瓶颈期了,很难再有突破
  2. 学习复杂度有什么用呢?
    1. 主要是在面试中和校招中考察。
    2. 其实再写一个算法的时候可以进行大概的估算

2. 时间复杂度

  1. 算法的时间复杂度是一个数学函数,定量描述了该算法的运行时间
  2. 每个机器的运行速度都不一样,不同的机器跑一样的代码,时间上会有差异
  3. 所以这个时候有了时间复杂度,时间复杂度计算的是程序执行的次数(大概的次数)
  4. 下面举个最简单的例子,下面代码的复杂度是多少?看时间复杂度,循环嵌套循环的复杂度就是 N^2
  5. 这个得出N^2,是因为在程序执行的时候,假设每执行100次,100次里的第一个循环就要执行100次,外层循环每次执行一次,里面的for循环就要执行100次
int main()
{int n = 100000,count = 0;for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){count++;}}printf("%d", count);return 0;
}

2.1. 大0的渐进表示法

  1. 看下面图来说,当 N 值越来越大的时候,2 * N + 10的部分影响就很小了

  1. 因为计算机运行的速度很快,比如我这个电脑运行速度是3.10GHz,也就意味着,在一段时间周期内可以处理3.1亿次指令,对于电脑来说多处理十几万的次数可谓相当轻松。
  2. 大O渐进法,就是对影响结果最大的值进行估算,只要保留最高项就行
  3. 再举个例子 1.N^2 + 2n; 2.N + 100; 3. N^3 。当N在10和100像这种比较小的数的时候,此时他们时间复杂度是差不多的。

2.2. clock 函数 <time.h>

  1. 返回程序消耗的处理器时间 ,单位 毫秒(ms)。
  2. 我的电脑,处理10亿次指令,用2075ms,2秒多。大家有兴趣,也可以用这个函数去试试

2.3. 例题

  1. 0 ms表示,运行时间小于1 ms
  2. 那么下面的时间复杂度是多少呢?时间复杂度计算的是大概的执行次数。是 F(N) = 2 * N + M; 用大O渐进法就是 O(N);
  3. 得出O(N),因为我们要省略对结果影响不大的值
void Func2(int N)
{int count = 0;for (int k = 0; k < 2 * N; ++k){++count;}int M = 10;while (M--){++count;}printf("%d\n", count);
}

2.3.1. 第二题

  1. 最好的情况就是一方远大于另一方

void Func3(int N, int M){int count = 0;for (int k = 0; k < M; ++ k){++count;}for (int k = 0; k < N ; ++ k){++count;}printf("%d\n", count);}

2.3.2. 第三题

  1. 那么这里是多少?,这个O(1), 这里意思不是执行1次,也不是执行时间低于1ms,而是这里的 1,表示常数次(常数就是1,2,3,4,5,...)
void Func4(int N){int count = 0;for (int k = 0; k < 100; ++ k){++count;}printf("%d\n", count);}

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

  1. 推导大O阶方法:
    1. 用常数1代替运行时的所有加法常数
    2. 去掉其他影响不大的项,只要保留最高阶项
    3. 如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。
  2. 本质:计算算法复杂度(次数) 属于哪个量级(level)
  3. 假如有两个富豪,一个有2000亿,另一个有3000亿,都去买咖啡喝,不管是便宜的200左右的,还是5000的,就算是50w的。富豪都买的起,意思想表达的就是富豪们都是属于一个级别的你买起,那么他也买的起,这点钱就无足轻重了

常见算法复杂度如下:

2.5. 复杂度的最好、平均和最坏

  1. 最坏情况:任意输入规模的最大运行次数(上限)
  2. 平均情况:输入任意数,期望的运行次数
  3. 最好情况:输入任意数,最小的运行次数(下限)

例如:在长度N的数组中查找一个数据

  1. 最好的情况 O(1),最坏的情况O(N),平均情况 N/2.

2.6. 例题,消失的数字

  1. 此题共提供两种思路
    1. 第1种:用按位或,先按位或上
    2. 第2种:所有项数相加,然后依次减去数组里的值,减去剩下来的值就是,单生狗

//方法1
int missingNumber(int* nums, int numsSize){int one = 0,second = 0;for(int i = 0;i <= numsSize;++i)//numsSize <= 多一个{one ^= i;}for(int j = 0;j < numsSize;j++){second ^= nums[j];}return one ^ second;
}
//方法2
int missingNumber(int* nums, int numsSize){int N = numsSize;//等差数列项数 resultint ret = (0 + N) * (N + 1) / 2; // N + 1 是因为确实的那个项for(int i = 0;i < numsSize; i++){ret -= nums[i];//ret 项数的总和,依次减去数组内的数}return ret;
}
  1. 图中是挨个异或,这里代码中直接先将0 - n,全部异或。然后再异或原数组,最有将两个异或,就得到了这个数

2.7. 轮转数组

  1. 循环条件是 left < right; //不用写 left <= right,当时单数的时候,交不交换都一样。,因为两边向中间靠拢交换
  2. 要画图,画清楚图代码都是水到渠成了
  3. 一定要注意,数组下标绝对不能是负数

void reverse(int* nums,int left, int right)
{while(left < right)//比较的下标值{int tmp = nums[left];nums[left] = nums[right];nums[right] = tmp;left++;right--;}
}
void rotate(int* nums, int numsSize, int k) {k %= numsSize;// k % numsSize 6 % 7 = 6reverse(nums,0,numsSize - k - 1);reverse(nums,numsSize - k,numsSize - 1);reverse(nums,0,numsSize - 1);
}

2.7.1. 还有一种方法,额外开辟空间

  1. 就是你们常说的用空间换时间,这个的空间复杂度是O(N),为什么是N,因为malloc开辟的空间是未知的
  2. 只要根据上面画的图,稍微推断一下就知道了
  3. 如果还不知道memcpy怎么使用的可以去看看 ,这篇博客C语言的内存函数
void rotate(int* nums, int numsSize, int k) {k %= numsSize;int* numsby = (int*)malloc(sizeof(int) * numsSize);//拷贝到新空间的前三个memcpy(numsby,nums + (numsSize - k),sizeof(int) * k);//把剩下的拷贝memcpy(numsby + k,nums,sizeof(int) * (numsSize - k));//把新空间的拷贝会numsmemcpy(nums,numsby,sizeof(int) * numsSize);free(numsby);numsby = NULL;
}

2.8. logN复杂度

int main()
{int n = 8;int count = 0, i = 1;for (i = 1; i < n; i *= 2){count++;}printf("%d\n", count);return 0;
}
  1. 二分查找的每次区间变化是 N / 2,每次查找都是N /2 /2 /2...
int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9 };int sz = sizeof(arr) / sizeof(arr[0]);int left = 0, right = sz - 1;int k = 7;while (left <= right)//为啥有等于因为,为单数时还有一个数需要查找{int mid = left + (right - left) / 2;if (arr[mid] < k)//左半没有我需要的值left = mid + 1;else if (arr[mid] > k)//被查找的值小于中间值,此时说明右半区间没有需要的值right = mid - 1;else{printf("%d", mid);break;}left++;right--;}return 0;
}

2.9. 乘阶的复杂度

  1. 乘阶的复杂的是 N + 1,算的是函数的调用次数总和 ,所以就是O(N)。
// 计算阶乘递归Fac的时间复杂度?
long long Fac(size_t N){if(0 == N)return 1;return Fac(N-1)*N;}
  1. 如果乘阶里面还有计算呢?
long long Fac(size_t N){if(0 == N)return 1;for(int i; i < N;i++){;}return Fac(N-1)*N;}
  1. 这个时候每调用一次,for循环就会打印 N次,这个消耗也要算进去,而且这个是递归调用,每次调用自身都会打印 n - 1次的数据,直到满足结束条件。
  2. 所以在这个递归调用里,复杂度是 O(N^2);。所有递归次数累加

2.10. 斐波那契的复杂度

int Fib(int n)
{if (n < 3)return 1;return Fib(n - 1) + Fib(n - 2);
}int main()
{//斐波那契int ret = Fib(40);printf("%d ", ret);return 0;
}
  1. 对此上面的方法只有理论意义,并不具有实际意义
  2. 所以我们要用迭代的方法O(N),来解决,这个方法更好
int main()
{//斐波那契//迭代的方法,因为斐波那契前两项都是1unsigned long long x1 = 1;unsigned long long x2 = 1;unsigned long long x3 = 0;int n = 1150;for (int i = 3; i <= n; i++){x3 = x1 + x2;x1 = x2;x2 = x3;}printf("%lld", x3);return 0;
}
  1. 这种迭代的方法还是不够好,算较小的数还行,数字大了还是不行,会到类型上限
  2. 可以用字符串存储,只要空间够大,多大的数都能存储。不过还没学到,下次一定!!

3. 空间复杂度

  1. 一个算法重点关注时间复杂度,不太关注空间复杂度,除非是嵌入式那些有大小限制的设备上。
  2. 空间复杂度算的是变量的个数,因为每个变量的差异不大,为什么没有什么差异?,举个例子
    1. 1GB = 1024MB;1MB = 1024KB 1 KB = 1024 Byte ;1Byte = 8bit;
    2. 一个MB的空间都有这么大了,还在乎这么点空间吗?
  3. 空间复杂度使用的也是大O渐进法。
  4. 可以来看看实例 ,函数的形参部分的变量不算个数,算的是函数内额外的变量个数
  5. 在此题目中冒泡排序里面,发现只开辟了三个变量,空间复杂度是O(1)
void bbu(int a[], int len)
{for (int i = 0; i < len - 1; i++){for (int j = 0; j < len - i - 1; j++){if (a[j] < a[j + 1]){int tmp = a[j];a[j] = a[j + 1];a[j + 1] = tmp;}}}
}

3.1. 空间复杂度 O(N)

  1. 实际上空间复杂度比时间复杂度更加容易计算
  2. 常见的空间复杂度只有三个,O(1) O(N) O(N^2);但是也有其他的
  3. 举个空间复杂为O(N)的例子
  4. 每次函数的调用都会创建一个栈帧,创建了多少个栈帧就是多大的空间,会调用N次,O(N)了
// 计算阶乘递归Fac的空间复杂度?
long long Fac(size_t N)
{if(N == 0)return 1;return Fac(N-1)*N;
}

总结:个人觉得可能会不太详细,但是重点部分都没拉下

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

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

相关文章

【深度学习实战(31)】模型结构之CSPDarknet

文章目录 一、CSPDarknet整体结构二、CSPNet结构2.1 里面小残差结构Bottleneck2.2 外层大残差结构CSP 三、SPP结构四、CSPDarknet结构4.1 stem结构4.2 dark2,3,4结构&#xff0c;dark3为例&#xff1a;4.3 dark5结构4.4 CSPDarkNet整体结构 四、完整代码 一、CSPDarknet整体结构…

通过DataGrip将mysql表结构信息转存excel 复制select结果的insert插入语句

各位小伙伴们大家好&#xff0c;欢迎来到这个小扎扎的专栏 总结 | 提效 | 拓展&#xff0c;在这个系列专栏中记录了博主在学习期间总结的大块知识点&#xff0c;以及日常工作中遇到的各种技术点 ┗|&#xff40;O′|┛ &#x1f306; 内容速览 1 查询表结构信息&#xff0c;并…

[安洵杯 2019]JustBase(替换表)

题目&#xff1a; 我们看到题目是一些杂乱的字母和符号&#xff0c;但从题目和末尾的两个号&#xff0c;我们猜测是base64加密&#xff0c;但题目未出现1-9数字&#xff0c;而base64不包含!#$%等字符&#xff0c;所以我们考虑将字符!#$%按照键盘替换成数字1-9. 替换代码如下&a…

基于光伏电站真实数据集的深度学习预测模型(Python代码,深度学习五个模型)

效果视频链接&#xff1a;基于深度学习光伏预测系统&#xff08;五个模型&#xff09;_哔哩哔哩_bilibili 界面设计 注册界面 登录界面 主界面 展示界面 1.数据集来源 The SOLETE dataset 这里分别保存了不同间隔采样时间表格 1min是以1min 间隔采集的数据集 数据集截图&…

Java 中的 pyftpdlib 替代品

在 Java 中&#xff0c;有一些替代方案可以用来实现 FTP 服务器功能&#xff0c;类似于 Python 中的 pyftpdlib。目前我们常用的就是三种替换方案&#xff0c;这里需要根据自己的项目需求选择合适的方法。 1、问题背景 在 Java 环境下寻找一款与 pyftpdlib 类似的 FTP 服务器库…

企业开发基础--数据库

今天完成了数据库学习的全部内容&#xff0c;在事务&#xff0c;索引&#xff0c;范式中要有个人逻辑上的理解&#xff0c;也算是卡着点完成了大多数预期&#xff0c;还有一个Java游戏未完成&#xff0c;会后续补上。 之后的一周要完成34道数据库练习题以及JDBC&#xff0c;学…

ip地址快速切换软件是什么

ip地址快速切换软件是什么&#xff1f;随着互联网的发展&#xff0c;IP地址变得愈发关键。对于网络工作者、营销人员和游戏玩家&#xff0c;频繁更换IP地址成了日常工作需求。为满足这一需求&#xff0c;IP地址快速切换软件如虎观代理IP软件应运而生&#xff0c;它为用户提供了…

避雷!7.7分,新增1区TOP被标记On Hold,5本已被踢除!

本周投稿推荐 SSCI • 2/4区经管类&#xff0c;2.5-3.0&#xff08;录用率99%&#xff09; SCIE&#xff08;CCF推荐&#xff09; • 计算机类&#xff0c;2.0-3.0&#xff08;最快18天录用&#xff09; SCIE&#xff08;CCF-C类&#xff09; • IEEE旗下&#xff0c;1/2…

低代码技术的深度应用:物资管理的创新与效率提升

引言 在当今企业运营中&#xff0c;物资管理扮演着至关重要的角色。无论是制造业、零售业还是服务行业&#xff0c;有效的物资管理都是确保业务正常运转和持续发展的关键。然而&#xff0c;随着企业规模的扩大和业务的复杂化&#xff0c;物资管理也变得越来越复杂。企业需要管…

Day05-JavaWeb开发-请求响应(postman工具/参数/案例)分层解耦(三层架构/IOC-DI引入)

1. 请求响应 1.1 概述 1.2 请求-postman工具 1.3 请求-简单参数&实体参数 1.3.1 简单参数 1.3.2 实体参数 1.4 请求-数组集合参数 1.5 请求-日期参数&json参数 1.6 请求-路径参数 1.7 响应-ResponseBody 1.8 响应-案例 2. 分层解耦 2.1 三层架构 2.2 分层解耦(IOC-D…

流畅的python-学习笔记_序列

概念 抽象基类&#xff1a;ABC, Abstract Base Class&#xff0c;ABC还有一个概念&#xff0c;是一个编程语言 序列 内置序列类型 分类 可分为容器类型和扁平类型 容器类型有list&#xff0c; tuple&#xff0c; collections.deque等&#xff0c;存储元素类型可不同&…

实验九 Java 语言网络通信程序设计练习(课内实验)

一、实验目的 本次实验的主要目的是练习网络通信程序的设计方法&#xff0c;并掌握计算机网络基 础知识、Java语言网络通信程序类库的结构和使用方法。 二、实验要求 1. 认真阅读实验内容&#xff0c;完成实验内容所设的题目。 2. 能够应用多种编辑环境编写Java语言源程序…

南京观海微电子---电源,从微观角度观看电功率是怎么产生

从微观角度看看无功功率是怎么产生的&#xff0c;在此之前&#xff0c;我们得先知道引起无功功率的元器件是储能器件&#xff0c;主要是电感和电容。 首先&#xff0c;在宏观上&#xff0c;我们知道电感能导致电压超前电流90&#xff0c;可从如下公式推出&#xff1a; 由此可以…

强到离谱!AI绘画Stable Diffusion让商业换装如此简单!AI一键换装,AI绘画教程

今天给大家介绍一款可以让 Stable Diffusion 轻松实现AI一键换装的超强插件—— Inpaint Anything &#xff0c;它能精准地替换图片中的指定部位&#xff0c;不仅上手简单&#xff0c;而且简直强到离谱&#xff01; 首先&#xff0c;我们要下载这个插件。插件可看文末扫描获取…

【ARM Cortex-M3指南】7:嵌套向量中断控制器和中断控制

文章目录 七、嵌套向量中断控制器和中断控制7.1 嵌套向量中断控制器概述7.2 基本的中断配置7.2.1 中断使能和清除使能7.2.2 中断设置挂起和清除挂起7.2.3 优先级7.2.4 活跃状态7.2.5 PRIMASK和FAULTMASK特殊寄存器7.2.6 BASEPRI特殊寄存器7.2.7 其他异常的配置寄存器 7.3 设置中…

LSTM计算指示图

掌握网络结构组件构成 输入门、遗忘门、输出门候选记忆细胞记忆细胞隐藏状态ref&#xff1a;6.8. 长短期记忆&#xff08;LSTM&#xff09; — 《动手学深度学习》 文档 (gluon.ai)

【论文阅读笔记】Order Matters(AAAI 20)

个人博客地址 注&#xff1a;部分内容参考自GPT生成的内容 论文笔记&#xff1a;Order Matters&#xff08;AAAI 20&#xff09; 用于二进制代码相似性检测的语义感知神经网络 论文:《Order Matters: Semantic-Aware Neural Networks for Binary Code Similarity Detection》…

一分钱不花从HTTP升级到HTTPS

HTTP升级到HTTPS是一个涉及安全性和技术实施的过程&#xff0c;主要目的是为了提升网站数据传输的安全性&#xff0c;防止数据被窃取或篡改。以下是一些关于从HTTP升级到HTTPS的技术性要点和步骤概述&#xff0c;结合上述信息资源&#xff1a; 一、理解HTTPS的重要性 HTTPS (…

IDEA--debug

1. 单点调试的三个级别 Step into&#xff1a;在单步执行时&#xff0c;遇到子函数就进入并且继续单步执行。Step over&#xff1a;在单步执行时&#xff0c;在函数内遇到子函数时不会进入子函数内单步执行&#xff0c;而是将子函数整个执行完再停止&#xff0c;也就是把子函数…

[图解]SysML和EA建模住宅安全系统-01

1 00:00:00,980 --> 00:00:03,100 接下来&#xff0c;我们来看一下案例 2 00:00:04,930 --> 00:00:06,750 我们这次课程的案例 3 00:00:07,090 --> 00:00:13,800 选用了SysML实用指南的书上 4 00:00:13,810 --> 00:00:16,180 第十七章这个案例 5 00:00:16,350 …