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

news2024/11/25 20:45:33

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

文章目录

  • 1.算法效率
    • 1.1 如何衡量一个算法的好坏
    • 1.2 算法的复杂度
  • 2.时间复杂度
    • 2.1时间复杂度的概念
    • 2.2 大O的渐进表示法
    • 补充
    • 2.3 leetcode练习题
    • 方法1
    • 方法2(重点)
    • 方法3
  • 结尾

1.算法效率

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

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

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

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

1.2 算法的复杂度

算法在编写成可执行程序后,运行时需要耗费时间资源和空间(内存)资源 。因此衡量一个算法的好坏,一般是从时间和空间两个维度来衡量的,即时间复杂度和空间复杂度。
时间复杂度主要衡量一个算法的运行快慢,而空间复杂度主要衡量一个算法运行所需要的额外空间
。在计算机发展的早期,计算机的存储容量很小。所以对空间复杂度很是在乎。但是经过计算机行业的迅速发展,计算机的存储容量已经达到了很高的程度。所以我们如今已经不需要再特别关注一个算法的空间复杂度。

注意:在不同的计算机上执行相同的代码也会因为计算机硬件的不同而花费不同的时间。
比如我们进行一个数量较多的冒泡排序,在 i3,1g内存的机器和 i9,16g内存的机器上花费的时间肯定不同

2.时间复杂度

2.1时间复杂度的概念

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

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

请计算一下Func1中++count语句总共执行了多少次?
void Func1(int N)
{
int count = 0;
for (int i = 0; i < N ; ++ i)
{
 for (int j = 0; j < N ; ++ j)
 {
 ++count;
 }
}
 
for (int k = 0; k < 2 * N ; ++ k)
{
 ++count;
}
int M = 10;
while (M--)
{
 ++count;
 }
 printf("%d\n", count);
}

Fun进行了一次N * N 的循环,一次 2*N 的循环和一次 10 次的循环
即 Fun=(N * N) + (2 * N) + 10

  • 当 N = 10 , F(N) = 130
  • 当 N = 100 , F(N) = 10210
  • 当 N = 1000 ,F(N) = 1002010

我们发现,随着N的增大,后面项对结果的影响越小,所以实际中我们计算时间复杂度时,我们其实并不一定要计算精确的执行次数,而只需要大概执行次数,那么这里我们使用大O的渐进表示法

2.2 大O的渐进表示法

大O符号(Big O notation):是用于描述函数渐进行为的数学符号。
推导大O阶方法:
1、用常数1取代运行时间中的所有加法常数。
2、在修改后的运行次数函数中,只保留最高阶项。
3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。
使用大O的渐进表示法以后,Func1的时间复杂度为:**O(N^2)

N = 10 F(N) = 100
N = 100 F(N) = 10000
N = 1000 F(N) = 1000000
通过上面我们会发现大O的渐进表示法去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数。

练习1:

计算Func2的时间复杂度?
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);
}

Fun2一共执行了2n+10次,所以它的时间复杂度是O(N)

练习2:

计算Func3的时间复杂度?
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);
}

Fun3一共执行了M+N次,由于我们不知道M和N的关系,可能M特别大,可能N特别大,也可能它俩一样大,M和N都会影响整个程序运行的时间,而M和N又是未知的,所以Fun3的时间复杂度是O(M+N)

练习3:

计算Func4的时间复杂度?
void Func4(int N)
{
 int count = 0;
 for (int k = 0; k < 100; ++ k)
 {
 ++count;
 }
 printf("%d\n", count);
}

Fun4执行了100次,为常数次,所以它的时间复杂度为O(1)

练习4:

计算strchr的时间复杂度?
const char * strchr ( const char * str, int character );

strchr就是用来从一个字符串中找某个特定的字符,可能一开始就找到了,也可能很久都没找到,但是我们在求时间复杂度的时候一般都是按照最坏打算来求的,也就是未知N次。它的时间复杂度为O(N)

补充

有些算法的时间复杂度存在最好、平均和最坏情况:
最坏情况:任意输入规模的最大运行次数(上界)
平均情况:任意输入规模的期望运行次数
最好情况:任意输入规模的最小运行次数(下界)
例如:在一个长度为N数组中搜索一个数据x
最好情况:1次找到
最坏情况:N次找到
平均情况:N/2次找到
在实际中一般情况关注的是算法的最坏运行情况,所以数组中搜索数据时间复杂度为O(N)
所以一般我们要降低预期,用底线思维

练习5:

计算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;
 }
}

在冒泡排序中会从第一个数开始不断的进行两个数的比较,然后不断的把大数排在后面,所以每次比较的次数会减一,所以冒泡排序整体进行的次数为一个等差数列,用等差数列公式即 N * (1+N) / 2。它的最高项为N ^ 2,所以冒泡排序的时间复杂度为O(N ^ 2).

练习6:


计算strchr的时间复杂度?
const char * strchr ( const char * str, int character );
// 计算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;
 }
}
// 计算BinarySearch的时间复杂度?
int BinarySearch(int* a, int n, int x)
{
 assert(a);
 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;
}

二分查找就是每次除以2嘛,2 ^ x = n,则 x = log n 。时间复杂度就为O(logN)。

注意:当我们想在一个有序数列找一个特别大的数时,暴力查找可能要进行几百万或者几亿次查找,而二分查找只用几十次就可以了(有没有感觉二分查找很厉害)
注:qsort的时间复杂度为(N*logN),后面我们会讲到的

在这里插入图片描述
练习7:

 计算阶乘递归Fac的时间复杂度?
long long Fac(int N)
{
 if(0 == N)
    return 1;
 for(int i = 0;i < n; i++)
 {
   //....
 }
 
 return Fac(N-1)*N;
}

Fac一共进行N次递归,每次递归会进行N(当前的N)次循环,即进行1次,2次…N次循环,所以它的本质也是一个等差数列,时间复杂度为O(N^2)
在这里插入图片描述

2.3 leetcode练习题

数组nums包含从0到n的所有整数,但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗?力扣 ,消失的数字

方法1

我们可以把整个数组进行排序,然后遍历。如果下一个数不是上一个数+1,则上一个数+1就是消失的数,这个方法大家可以自己尝试一下,我们就不写了

方法2(重点)

异或法:首先将sums所有的数进行异或(^)得到number1,number1再异或从0~n的数字得到number2,则得到的number2就是最终消失的那个数

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

方法3

等差数列求和法:我们可以通过等差数列求出0—n的值,然后减去数组的每一个元素,剩下的就是消失的数字

int missingNumber(int* nums, int numsSize)
{     
    int add_1 = 0;
    int add_2 = 0;
    add_1 = ( (0 + numsSize) * (numsSize + 1) ) / 2;
    for(int i = 0; i < numsSize; i++)
    {
         add_2 += nums[i];
    }
    return add_1 - add_2;
}

结尾

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

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

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

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

相关文章

智慧园区系统未来发展前景及应用趋势分析

完善的系统功能&#xff0c;强大的技术支持&#xff0c;使得智慧园区的应用趋势更加多元化&#xff0c;下面我们一起来了解一下智慧园区系统未来发展前景及应用趋势。 1、人工智能。人工智能技术是智慧园区未来发展的重要方向。人工智能可以帮助园区更好地解决实际问题&…

Docker笔记1 | Docker学习和简介

1 | Docker学习和简介1 学习来源2 官方学习资源3 Docker简介3.1 Docker是什么&#xff1f;3.2 Docker应用场景3.3 Docker架构3.3 Docker的优势3.3 与传统虚拟机的区别1 学习来源 本系列笔记学习主要参考书籍《Docker-从入门到实践》以及结合官网的教程&#xff0c;仅作为个人学…

电脑开机后进不了系统怎么办?

案例&#xff1a;我的电脑开机之后&#xff0c;进入不了系统怎么办&#xff1f; 【今天我打开电脑时&#xff0c;发现进入不了系统&#xff0c;以前从来没有出现过这种情况。有没有小伙伴有解决的办法&#xff1f;在线等&#xff0c;急&#xff01;】 电脑开机后无法进入系统…

node 服务发布后无法访问

node 服务发布后无法访问问题描述&#xff1a;在本地环境访问ip3060端口能正常访问&#xff0c;部署到服务器后访问接口一直超时 解决方法&#xff1a; 看端口是否对外暴露 操作步骤 设置防火墙 点击Windows defender 防火墙 点击高级设置 点击入站规则 新建规则 将3060端口…

《程序员面试金典(第6版)》面试题 10.10. 数字流的秩

题目描述 假设你正在读取一串整数。每隔一段时间&#xff0c;你希望能找出数字 x 的秩(小于或等于 x 的值的个数)。请实现数据结构和算法来支持这些操作&#xff0c;也就是说&#xff1a; 实现 track(int x) 方法&#xff0c;每读入一个数字都会调用该方法&#xff1b; 实现 g…

全球首个完全开源的指令跟随大模型;T5到GPT-4最全盘点

1. Dolly 2.0&#xff1a;世界上第一个完全开源的指令跟随LLM 两周前&#xff0c;Databricks发布了类ChatGPT的大型语言模型 (LLM)Dolly&#xff0c;其训练成本不到 30 美元。今天&#xff0c;他们发布了 Dolly 2.0&#xff0c;这是业内第一个开源的指令跟随LLM&#xff0c;并根…

飞项的5种应用方法,帮助你轻松学会项目管理

随着时代的更新变化&#xff0c;在现代企业中&#xff0c;项目管理已经成为一项非常重要的能力考核。 而对于刚开始入门项目管理的新手&#xff0c;很多都不知道从哪里入手&#xff0c;怎么入手。同执行者相比&#xff0c;管理者所思考的维度又大不相同&#xff0c;接下来我们就…

java实现定时器的方法

大家在工作中&#xff0c;常常会遇到一些突发的工作&#xff0c;需要在短时间内完成。这就要求我们能够快速的处理这些突发事件&#xff0c;但是如果直接调用方法来做&#xff0c;时间太长了&#xff0c;会导致程序变得臃肿。那么有没有什么好的办法呢&#xff1f;下面我们就来…

notepad++在windows下使用mingw编译C语言

mingw下载链接&#xff1a;https://winlibs.com/ 官网https://www.mingw-w64.org也能下载&#xff0c;不过官网下载的那个不会用&#xff0c;以后再试了。 strawberry里面也集成了gcc编译器&#xff0c;使用它也可以编译&#xff0c;只是试了一下。 解压后有1个多G&#xf…

python入门(五) vscode配置Anaconda 环境,代码自动提示

文章目录1.conda的下载地址:1.配置conda的环境变量安装conda配置path2.vcode配置python插件3.配置conda1) Select Interpreter2) 选择conda环境4.测试vscode配置Anaconda 环境&#xff0c;代码自动提示. 本人工作中&#xff0c;用到了ai相关技术&#xff0c;但是java出身&#…

400元左右的蓝牙耳机哪个牌子好?400以内的蓝牙耳机推荐

目前市面上的真无线耳机是百花齐放&#xff0c;小巧的无线蓝牙耳机携带方便&#xff0c;已经成为很多人生活的标配产品&#xff0c;通勤、办公、音乐、游戏方方面面都离不开TWS耳机。近两年&#xff0c;TWS耳机飞速发展&#xff0c;各方面的功能和体验均已完善&#xff0c;因此…

06_GBDT+LR论文翻译

0.摘要 在线广告允许广告客户仅针对可衡量的用户响应进行出价和付费&#xff0c;例如广告点击。因此&#xff0c;点击预测系统是大多数在线广告系统的核心。伴随每日活跃用户超过7.5亿&#xff0c;活跃广告客户超过100万的情况&#xff0c;预测Facebook广告点击是一项具有挑战…

AI加持,让图片处理更加得心应手

AI图片处理工具不仅能够帮助我们更高效地完成图片编辑和设计任务&#xff0c;还能够通过机器学习和深度学习技术生成出独特的图片和视觉效果。本期日报为大家带来了几款非常不错的AI图片工具&#xff0c;它们能够让你在创作中更具创意和想象力。不要再犹豫了&#xff0c;赶紧来…

Yolo V7详解及openvino部署

论文: https://arxiv.org/abs/2207.02696 代码: https://github.com/WongKinYiu/yolov7 Anchor Anchor是一种用于目标检测的先验框(prior box)生成方法&#xff0c;由Ren等人在2015年提出。Anchor可以在不同尺度和不同纵横比下生成多个先验框&#xff0c;并通过与真实目标框的…

工程项目管理系统源码-全面的工程项目管理

​ ​工程项目管理系统是指从事工程项目管理的企业&#xff08;以下简称工程项目管理企业&#xff09;受业主委托&#xff0c;按照合同约定&#xff0c;代表业主对工程项目的组织实施进行全过程或若干阶段的管理和服务。 如今建筑行业竞争激烈&#xff0c;内卷严重&#xff0c…

第17章_反射机制

第17章_反射机制 讲师&#xff1a;尚硅谷-宋红康&#xff08;江湖人称&#xff1a;康师傅&#xff09; 官网&#xff1a;http://www.atguigu.com 本章专题与脉络 1. 反射(Reflection)的概念 1.1 反射的出现背景 Java程序中&#xff0c;所有的对象都有两种类型&#xff1a;编…

shell命令总结

目录ls - 查看目录cd - 切换目录whereis - 查看是否有指定目录touch - 创建空文件mkdir - 创建目录cp - 复制文件或目录mv - 移动文件、更名rm - 删除文件cat - 显示文件内容more - 分页显示文件内容head - 查看文件前N行tail - 查看文件的后几行ln - 产生链接文件chomd - 改变…

图片转pdf无水印版怎么转换?快收藏这三种免费转换方法!

图片转pdf无水印版怎么转换&#xff1f;在日常生活中&#xff0c;为了节省批量图片发送的时间&#xff0c;我们通常会将多张图片转换成PDF文件格式文档&#xff0c;然后发送给他人。 目前在市场上有很多软件可以将图片转PDF。你想知道哪个软件可以将图片转PDF没有水印吗&#…

【生活工作经验 十】ChatGPT模型对话初探

最近探索了下全球大火的ChatGPT&#xff0c;想对此做个初步了解 一篇博客 当今社会&#xff0c;自然语言处理技术得到了迅速的发展&#xff0c;人工智能技术也越来越受到关注。其中&#xff0c;基于深度学习的大型语言模型&#xff0c;如GPT&#xff08;Generative Pre-train…

Spring创建和使用

日升时奋斗&#xff0c;日落时自省 目录 1、创建Spring项目 1.1、创建Maven项目 1.2、添加Spring框架支持 1.3、添加启动类 2、存储Bean对象 2.1、创建Bean 2.2、将Bean注册到容器 3、获取并使用Bean对象 3.1、创建Spring上下文 3.2、获取指定的Bean对象 3.2.1、Id…