算法复杂度详解( 超详细!)

news2025/4/21 19:12:14

前言:

  今天,小编正式开始学习了数据结构的正式内容,学习了算法复杂度相关的内容,为了加强对这个的了解,于是诞生了这一篇文章,下面废话不多说,开始进入复杂度的详解!

目录:

1.算法的效率

1.1.旋转数组习题讲解

1.2.复杂度的概念与分类

2.时间复杂度

2.1.函数T(N)

2.2.大O的渐进表示法

2.3.大O相关练习题的详解

3.空间复杂度

3.1.空间复杂度的计算方法

3.2.相关例题的详解

正文:

1.算法的效率

1.1.旋转数组习题讲解

  首先,读者朋友们肯定会很好奇旋转数组是什么东西,其实这是一个算法题所涉及到的内容,下面小编线给大家看一下这个题目:

    对于此题的详细内容上图已经给大家展示出来了,此题出自力扣,各位读者朋友们如果想要刷题的话,小编很推荐这个平台的题目,它的算法题还是有一定的难度的,学有余力的读者朋友可以看一下这个平台,小编这里先放上这个平台的链接:力扣 (LeetCode) 全球极客挚爱的技术成长平台

  废话不多说了,下面开始这个题的讲解:首先,这个题是指右轮数组中的数,其实就是把数组后k个元素放到开头,下面是小编画的图解,各位读者可以观看一下:

  所以我们可以保存数组最后一个数,通过while循环的方式,每此先把最后一个元素保存下来,然后在通过一次for循环来把第一个位置的数空出来(很像顺序表的头插操作),然后循环玩一次后,k减去一次,直到k变为0为止,这里便可以做到轮转操作,光说不展示代码等于白说,下面小编展示一下这个思路的代码展示:

void rotate(int* nums, int numsSize, int k) {
    int i = 0,end = 0;
    while(k--)
    {
        end = nums[numsSize - 1];
        for(i = numsSize - 1 ; i > 0 ; i--)
        {
            nums[i] = nums[i - 1];
        }
        nums[0] = end;    //三天没敲代码了差点没忘干净
    }
}

  可能许多读者朋友很好奇我为什么没有int main函数,其实这就是力扣题的特点,力扣的算法题,主要是让你补充完这个函数的,下面给大家展示一下做题页:

  可以这么想:力扣已经给你提供了int main函数,你接下来只需要把函数填充完,后续不用管,下面先来调试一下,看一下这个函数小编是否写对了:

  可以看出小编在测试的时候并没有错误,下面我们再试一下提交代码,看一下提交完代码后的结果是什么:

  可以看出,小编这个代码并没有通过,力扣也给出了这个题目的评判结果:这个题超出了时间限制,意思就是小编这个代码的运行时间过长,过于 复杂,导致这个题目出现了问题,所以说,小编这个代码并没有错,错的是运行时间过长,这个代码并没有符合这个题目运行时间要求,这里就涉及到了一个船新的知识点:时间复杂度出现的问题,下面开始进行复杂度的介绍!

1.2.复杂度的概念和分类

  算法在编写成可执行程序后,运⾏时需要耗费时间资源和空间(内存)资源 。因此衡量⼀个算法的
好坏,⼀般是从时间和空间两个维度来衡量的,即时间复杂度和空间复杂度。
  时间复杂度 主要是用来衡量一个算法的运行快慢,而 空间复杂度 主要是衡量一个算法运行所需要的额外空间,在很早的时候,由于计算机发展的还不算完善,运行内存是很低的,从而导致程序员们在编写程序的时候,很看重空间复杂度,不过随着科技的发展,计算机也在进行飞一般的提升,现在,空间复杂度已经没有那么重要了,但是还是有一定作用的,现在很多企业的招聘依旧喜欢考有关空间复杂度的题目。
  对于上面题目的错误,超出时间限制,涉及到了时间,所以很明显是时间复杂度出现问题了,那么到底出现了什么问题呢?不要着急,下面跟随小编的步伐,开始今天的大头——时间复杂度的介绍:

2.时间复杂度

2.1.函数T(N)

  在计算机科学中,时间复杂度其实是用一个函数时T(N)来进行表示的,时间复杂度计算的是时间运算的时间效率,由于函数的运行时间受到编译环境,设备,编译器的影响,所以我们通常是不计算代码的运行时间的,并且运行时间只能写好程序以后再去调试,不能够去推算!

  那么,函数T(N)到底是什么呢?其实函数式T(N)计算的是函数的执行次数,下面,小编通过一组代码,来给大家对于这个T(N)的初步的理解:

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

  各位读者朋友先来自己计算一下这个代码运行次数(其实就是循环次数),下面小编来给大家计算一下这个代码的运行次数:

  首先,我们从第一个循环开始看,这个是个循环的嵌套,所以一共进行了N * N次,也就是N ^ 2次,之后我们在看下一个循环,很显然,循环了2 * N次,所以一共有2N次,在看下一个循环,根据题目的意思,所以这里其实循环了10次,所以一共有 N ^ 2 + 2 * N + 10次,可能由于很多读者朋友会疑惑为什么在进行创建变量的时候不算次数,因为这个次数太小,所以可以忽略掉,小编下面就直接忽略这个了!并且由于计算机计算的高效率,我们可以仅仅保留其中的最大项,也就是这里其实一共循环了N ^ 2次!

  所以通过这个题我们可以看出,平时我们在计算时间复杂度的时候,计算的也不是精确值,而是粗略估计(拿我们只保留最高阶为例),在上面小编对于运行次数的计算的时候,有些读者朋友可能已经注意了小编对于低阶数的省略,不重要性,下面,小编将会讲述本文的大头,我们对于运行次数(循环次数)的计算,复杂度可以通过大O的渐进表示法来表示!

2.2.大O的渐进表示法

  大O符号:是用于描述函数渐进行为的数学符号

  下面小编先来展示一下大O阶的规则(这里小编偷懒直接用到官方描述):

  上面的图片便就是来对于大O如何进行使用的描述,其实这部分的内容,考察的是各位读者朋友们的数学知识,所以各位读者朋友一定要好好的去学习数学知识,下面为了巩固大家对于这个大O渐进表示法的理解,这里小编将给出几个例子,来帮助大家去进行了解!

2.3.大O相关习题的讲解:

  2.3.1.代码1:

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);
}

  老规矩,各位读者先自行做一下,小编稍后给大家进行讲解,下面小编将会给出这个题的详解:

  首先,我们先看第一个循环,一共循环了2N次,然后在看下一个循环,一共循环了10次,所以一共循环了2N + 10次,我们根据大O的第一个规则,所以我们要保留最高项,所以是2N,在看下一个规则,所以我们可以把最高项的系数去掉,所以最后得出来的结果是O(N)!对于这种复杂度的题,读者朋友们一定要好好的理解到,这对于我们进行一些算法题的练习中有很大的帮助!废话不多说,进入下一个题目的训练:

2.3.2.代码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);
}

  老规矩,各位读者朋友先自行阅读一下,下面小编给出这个复杂度的解释:

  首先,我们先看第一个循环,一共循环了M次;在看下一个循环,一共循环了N次,所以这个代码一共运行了M + N次,由于我们并不知道M,N的大小关系(这里M,N都是变量,不要只认为大N是变量!),所以大O使用法我们都用不了,所以最后的结果应该是0(M + N)次。读者朋友们可不要在这里犯错误,下面继续进行下一个练习!

2.3.3.代码3

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

  下面小编直接给出解释了:

  首先我们日常看第一个循环,很显然这个循环一共循环了100次,所以运行次数一共循环了100次,这里我们用了大O的第三个规则,对于是常量的循环次数,我们统一用O(1)来表示。废话不多说,我们开始进行下一个代码的练习:

2.3.4.代码4

    const char* strchr(const char* str, int character) {
        const char* p_begin = s;
        while (*p_begin != character) {
            if (*p_begin == '\0')
                return NULL;
            p_begin++;
        }
        return p_begin;
    }

  下面给出解释:

  这个算是一个比较难的复杂度的情况,因为这个是用来进行查找字符的函数,所以我们要进行分情况来讨论,下面先来第一种情况:

  第一种情况是所找的字符就在开头几个,此时我们仅仅循环几次就好了,所以这个可以称之为最好的情况,所以复杂度应该是0(1).

  第二种情况是所要找的字符串在中间附近,所以此时一共大约循环了N / 2次,为了与下面的复杂度进行区分,这里的时间复杂度我们用0(2 / N)来表示。这个可以称之为中等情况

  第三种情况是所要找的字符串在最后或者根本就不存在所想要找的字符串,这里一共循环了N        次,所以可以称之为最坏的情况,所以时间复杂度是0(N)次。

  对于我们如何进行时间复杂度的筛选,这里小编直接给出结果了,我们在计算时间复杂度的时候,要计算最坏情况下的时间复杂度,如果最坏的时间复杂度下的代码都过了的话,那么很显然其他情况也可以,读者朋友一定要记得这个知识点哟~~~下面我们进入下一个代码时间复杂度的练习!

2.3.5.代码5

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

  可能有些细心读者朋友已经认出小编写的这个代码是什么了,没错,这个代码就是冒泡排序,小编在之前写过,有兴趣的读者朋友可以进小编主页进行查看,废话不多说,下面进入解析部分:

  这个代码其实也可以分为三种情况,不过小编之前说过,计算时间复杂度,我们就要去计算最坏的情况(此时end也为n),那么就是完整的进行一次循环,下面小编通过图文的方式来告诉各位这个题的循环次数:

  所以其实一共循环了N * (N - 1) / 2次,经过大O规则后,最后的出来的时间复杂度是0(N ^ 2),这个算是比较典型的题目,读者朋友们一定要好好的去理解!下面我们进入下一个题目的训练

2.3.6.代码6

    void func5(int n) {
        int cnt = 1;
        while (cnt < n) {
            cnt *= 2;
        }
    }

   这个题目乍一看很简单,很多读者朋友会脱口而出:是O(N)!如果真这么写,那么就出大错喽!下面小编给出这个题目的解析:

  这个题目最大的坑就是循环内部的内容,cnt * 2,并且此时while循环就是通过cnt来进行定义的,所以这里循环次数与内部是息息相关的,我们这里可以通过数学的思想,将 = 右边的内容变成N,左边的内容变成2 ^ X,此时其实是2 ^ x = N,我们两边同时取对数,可以求出此时x等于log N(以2为底,不过我们再写复杂度的时候,同样也可以把2,底数给省略掉,因为如果N过于大的话,底数多大已经无所谓了!),所以应该是0(log N)!各位读者朋友可不要跳进这个题目的陷阱里,好了,以上便是对于时间复杂度的一些练习题,下面我们将要进入空间复杂度的练习!

3.空间复杂度

3.1.空间复杂度的计算方法

  首先,空间复杂度的计算方法其实和时间复杂度是差不多的,它们都是用的大O的渐进表示法,只不过时间复杂度是来计算运行次数的,而空间复杂度是来计算变量的个数的(这里涉及到了动态内存的开辟等等),这里值得一提的是:函数在运行时所需要的栈空间在编译期间已经确定好了,因此空间复杂度主要是针对于函数在运行的时候所申请的额外空间所确定的!

3.2.相关例题的详解

3.2.1.代码1

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

  这里又是我们熟悉的冒泡排序,只不过这里我们计算的是空间复杂度,此时我们遍历一下这个函数,此时函数的栈帧已经在编译时就确定好了,所以我们这里关注函数内部就好,很显然,这里我们就创立了exchange等一些局部变量,此时可以直到开辟的空间为一个常量,所以最后计算的大O应该是O(1)!其实空间复杂度相较于时间复杂度算是比较简单的了; 下面我们进入下一个习题的讲解!

3.2.2.代码2

    long long Fac(size_t N) {
        if (N == 0)
            return 1;
        return Fac(N - 1) * N;
    }

  首先很显然,这是一个函数递归的知识,而且计算的是阶乘的知识,下面我们继续来计算这个题的空间复杂度:

  此时我们不难知道,这里这个函数被调用了N次,所以应该开辟了N个函数栈帧,每个栈帧都有着相应的常数项空间,所以我们可以得出结论,空间复杂度应该是O(N)!

总结:

  此时,小编已经讲完了大部分关于复杂度的知识点,对于这部分内容,其实各位读者朋友没必要去死磕关于复杂度类型的习题,这部分的知识可以做几个来自己了解一下,毕竟复杂度的习题很考验各位的数学能力,大家先知道这是什么就好,至于对于其的计算,其实也就是算法题会涉及这个,大家做题时注意一下就好,好了,如果文章有错误的地方,恳请您在评论区指出,可能很多读者朋友会很好奇旋转数组怎么写才对,小编会在下一篇文章写这部分内容,那么,我们下一篇博客见喽!

 

 

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

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

相关文章

鸿蒙元服务API集全新呈现-开发更清晰高效

鸿蒙元服务API集全新呈现&#xff0c;开发更清晰高效&#xff0c;具体见如下截图&#xff0c;深黑色部分即本阶段公布支持的元服务API集。 本材料整理来源于HarmonyOS NEXT Developer Beta1官方公开的文档

银河麒麟(Kylin)KYSEC使用

1.推荐使用方法 *.临时禁用指令: setstatus disable--禁用 注&#xff1a;执行reboot后系统会自动启动 2.选用指令&#xff1a; *.永久禁用指令&#xff1a; setstatus disable -p *.重启后,KYSEC还是处理关闭关状态。 *.使用如下指令启用&#xff1a;setstatus enable …

慕尼黑电子展回顾:启明智显闪耀全场,多模态硬件智能体引领未来科技潮流

在刚刚落幕的慕尼黑电子展上&#xff0c;启明云端携启明智显与触觉智能两家子公司&#xff0c;共同为全球观众呈现了一场科技盛宴。本次展会&#xff0c;启明智显凭借其创新的多模态硬件智能体及一系列前沿产品&#xff0c;赢得了广泛关注与好评&#xff0c;展位现场人流如织&a…

基于java+springboot+vue实现的大学城水电管理系统(文末源码+Lw)106

基于SpringBootVue的实现的大学城水电管理系统&#xff08;源码数据库万字Lun文流程图ER图结构图演示视频软件包&#xff09; 系统功能&#xff1a; 本大学城水电管理系统 管理员功能有个人中心&#xff0c;用户管理&#xff0c;领用设备管理&#xff0c;消耗设备管理&#x…

基于Java+Vue的场馆预约系统源码体育馆羽毛球馆篮球馆预约

市场前景 市场需求持续增长&#xff1a;近年来&#xff0c;随着人们生活水平的提高和休闲娱乐需求的多样化&#xff0c;各类场馆&#xff08;如体育馆、图书馆、博物馆、剧院等&#xff09;的访问量不断增加。然而&#xff0c;传统的预约方式往往存在效率低下、信息不透明等问…

浅谈React

forwardRef和useImperativeHandle的联动使用 import React, { useImperativeHandle, useRef } from "react" import { forwardRef } from "react"const CustomInput forwardRef((props, ref) > {const inputRef useRef<HTMLInputElement>(null…

【以史为镜、以史明志,知史爱党、知史爱国】中华上下五千年之-宋朝(北宋)

宋朝&#xff08;960年—1279年&#xff09;是中国历史上承五代十国下启元朝的朝代&#xff0c;分北宋和南宋两个阶段&#xff0c;共历十八帝&#xff0c;享国三百一十九年。 北宋 赵匡胤&#xff08;宋太祖&#xff09;-赵光义&#xff08;宋太宗&#xff09;-赵恒&#xff08…

【MyBatis】——入门基础知识必会内容

&#x1f3bc;个人主页&#xff1a;【Y小夜】 &#x1f60e;作者简介&#xff1a;一位双非学校的大二学生&#xff0c;编程爱好者&#xff0c; 专注于基础和实战分享&#xff0c;欢迎私信咨询&#xff01; &#x1f386;入门专栏&#xff1a;&#x1f387;【MySQL&#xff0…

【初阶数据结构】树与二叉树:从零开始的奇幻之旅

初阶数据结构相关知识点可以通过点击以下链接进行学习一起加油&#xff01;时间与空间复杂度的深度剖析深入解析顺序表:探索底层逻辑深入解析单链表:探索底层逻辑深入解析带头双向循环链表:探索底层逻辑深入解析栈:探索底层逻辑深入解析队列:探索底层逻辑深入解析循环队列:探索…

文华财经盘立方博易大师boll布林带指标公式源码

TT:TIME>850&&TIME<1150; MID:MA(CLOSE,26);//求N个周期的收盘价均线&#xff0c;称为布林通道中轨 TMP2:STD(CLOSE,26);//求M个周期内的收盘价的标准差 TOP:MID2*TMP2;//布林通道上轨 BOTTOM:MID-2*TMP2;//布林通道下轨 A:EVERY(ISDOWN,2)&&TT&&…

SQL职场必备:掌握数据库技能提升职场竞争力

&#x1f482; 个人网站:【 摸鱼游戏】【网址导航】【神级代码资源网站】&#x1f91f; 一站式轻松构建小程序、Web网站、移动应用&#xff1a;&#x1f449;注册地址&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交…

Centos7下zabbix安装与部署

Centos7下zabbix安装与部署 一、Zabbix介绍 1、zabbix是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案 2、zabbix能监视各种网络参数&#xff0c;保证服务器系统的安全运营&#xff1b;并提供灵活的通知机制以让系统管理员快速定位/解决存在的各…

Android初学者书籍推荐

书单 1.《Android应用开发项目式教程》&#xff0c;机械工业出版社&#xff0c;2024年出版2.《第一行代码Android》第二版3.《第一行代码Android》第三版4.《疯狂Android讲义》第四版5.《Android移动应用基础教程&#xff08;Android Studio 第2版&#xff09;》 从学安卓到用安…

ICC2:no path与scenario status

我正在「拾陆楼」和朋友们讨论有趣的话题&#xff0c;你⼀起来吧&#xff1f; 拾陆楼知识星球入口 有星球小伙伴提问为什么pt能报出来path而ICC2报告不出来&#xff0c;排除两边sdc约束不同的问题&#xff0c;那就是ICC2并没有设置好scenario status&#xff0c;最后发现是没有…

Java接口案例

一案例要求&#xff1a; 二代码&#xff1a;(换方案只需要将操作类第二行的new新对象修改就能更改项目) Ⅰ&#xff1a;&#xff08;主函数&#xff09; package d1;public class test {public static void main(String[] args) {operator anew operator();a.show();a.averag…

从0开始的STM32HAL库学习2

外部中断(HAL库GPIO讲解) 今天我们会详细地学习STM32CubeMX配置外部中断&#xff0c;并且讲解HAL库的GPIO的各种函数。 准备工作&#xff1a; 1、STM32开发板&#xff08;我的是STM32F103C8T6&#xff09; 2、STM32CubeMx软件、 IDE&#xff1a; Keil软件 3、STM32F1xx/ST…

南京邮电大学运筹学课程实验报告3 整数规划问题求解 指导

一、题目描述 实验三 整数规划问题求解    实验属性&#xff1a; 设计型    实验目的 1&#xff0e;理解图的整数规划问题概念&#xff1b; 2&#xff0e;掌握运筹学软件的使用方法&#xff1b; 3. 掌握整数规划问题求解原理和方法。 实…

转:in-context learning浅显易懂解释

in-context learning的learning和 machine learning、deep learning、supervise learning、unsupervise learning不一样&#xff0c;这些learning是用梯度更新模型参数的。 context就是上下文的意思&#xff0c;就是你输入的上下文。in-context就是从你输入的上下文里学习到了…

短视频矩阵系统全解析:让获客变得更简单

随着数字媒体的迅猛发展&#xff0c;短视频已成为人们生活中不可或缺的一部分。对于企业而言&#xff0c;如何有效利用短视频平台吸引目标用户&#xff0c;实现高效获客&#xff0c;成为了一个亟待解决的问题。本文将全面解析短视频矩阵系统&#xff0c;带您领略其独特魅力&…

CTF php RCE(三)

0x07 日志文件包含 判断类型 使用kali curl -I urlF12 打开F12开发者工具&#xff0c;选中之后F5刷新查看server类型即可 配置文件 直接包含或者访问如果有回显就是&#xff0c; NGINX&#xff1a;NGINX 的配置文件通常位于 /etc/nginx/ 目录下&#xff0c;具体的网站配…