当前位置: 首页 > news >正文

算法复杂度

1. 数据结构前⾔

1.1数据结构

数据结构是计算机存储数据,组织数据的方式,指相互之间存在⼀种或多种特定关系的数
据元素的集合。常见的数据结构有线性表,树,图,哈希等。

1.2 算法

算法是一种计算过程,输入一些数据,通过一系列的计算,输出数据。

1.3 数据结构和算法的重要性

在一些工作岗位中,数据结构和算法是必需的。

很多大厂的笔试题都对数据结构和算法有严格的需求,因此我们要认真着手数据结构和算法。

那如何学好数据结构呢,

就是要多写代码,多思考,只能考一点一点的积累。

2. 算法效率

如何评判一个算法的好坏呢,从空间和时间两个方面去判断,即时间复杂度和空间复杂度。

时间复杂度评判根据一个算法的快慢,空间复杂度则根据一个算法所需开辟的空间大小。

在计算机发展的早期,计算机的存储容量很⼩。所以对空间复杂度很是在乎。但是经过计算机⾏业的
迅速发展,计算机的存储容量已经达到了很⾼的程度。所以我们如今已经不需要再特别关注⼀个算法
的空间复杂度。

2.2 复杂度的重要性

在企业的校招中,很多面试笔试都或多或少的设计到了复杂度。

3. 时间复杂度

定义:在计算机科学中,算法的时间复杂度是⼀个函数式T(N),它定量描述了该算法的运⾏时间。时
间复杂度是衡量程序的时间效率,那么为什么不去计算程序的运⾏时间呢?

在不同的编译环境下,在不同的运行环境下,相同的程序会有不同的运行时间,换句话说,有的机器比较好时间就会段,而有的机器比较慢,这样相同的程序就产生了不同的运行时间,因此研究运行时间的意义并不大。

那么算法的时间复杂度是⼀个函数式T(N)到底是什么呢?这个T(N)函数式计算了程序的执⾏次数。通
过c语⾔编译链接章节学习,我们知道算法程序被编译后⽣成⼆进制指令,程序运⾏,就是cpu执⾏这
些编译好的指令。那么我们通过程序代码或者理论思想计算出程序的执⾏次数的函数式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;
}
}

计算一下count++这条语句执行了多少次,

第一个循环嵌套执行N^2,第二个循环执行2N次,第三个循环执行10次,所以一共执行N^2+2N+10次。

Func1 执⾏的基本操作次数:
T (N) = N2 + 2 ∗ N + 10
• N = 10 T(N) = 130
• N = 100 T(N) = 10210
• N = 1000 T(N) = 1002010
通过对N取值分析,对结果影响最⼤
的⼀项是 N^2

在计算时间复杂度时,计算的也不是语句的执行次数,因为一条语句可能不止一条二进制语句,所以只通过计算执行次数是计算不出来的,因此,大O的渐进表示法就出现了。

3.1 ⼤O的渐进表⽰法

规则如下

推导⼤O阶规则
1. 时间复杂度函数式T(N)中,只保留最⾼阶项,去掉那些低阶项,因为当N不断变⼤时,
低阶项对结果影响越来越⼩,当N⽆穷⼤时,就可以忽略不计了。
2. 如果最⾼阶项存在且不是1,则去除这个项⽬的常数系数,因为当N不断变⼤,这个系数
对结果影响越来越⼩,当N⽆穷⼤时,就可以忽略不计了。
3. T(N)中如果没有N相关的项⽬,只有常数项,⽤常数1取代所有加法常数

通过大O表示法,就可以得到上述代码 的时间复杂度是O(N^2),因为2N和10对结果影响较小,所以就忽略不计了。

3.2 时间复杂度计算⽰例

3.2.1 ⽰例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);
}

简单分析下,时间复杂度为2N,10忽略不计,但是时间复杂度并不是2N,而是N,2对计算机影响并不大,参考第三条法则,所以最后时间复杂度就是O(N);

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

T(N)=M+N,在这里不确定m和n的关系,无法忽略,

m>>n,T(N)=M

m<<n,t(n)=N

m==n,t(N)=N

O(N)=m+n

3.2.3 ⽰例3

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

Func4循环只执行了100次,复杂度应该为100,根据第三条法则,只要是常数项通为O(1)

3.2.4 ⽰例4

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

很明显这是一个求字符串长度的函数,我们并不确定字符串的长度,可能为1,也可能为n,最坏的打算就是n,平均情况是n/2,也就是平均时间复杂度O(N)。

小总结

通过上⾯我们会发现,有些算法的时间复杂度存在最好、平均和最坏情况。
最坏情况:任意输⼊规模的最⼤运⾏次数(上界)
平均情况:任意输⼊规模的期望运⾏次数
最好情况:任意输⼊规模的最⼩运⾏次数(下界)
⼤O的渐进表⽰法在实际中⼀般情况关注的是算法的上界,也就是最坏运⾏情况。

3.2.5 ⽰例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次冒泡,第二个数据要经历n-1次,一直到第n个数据经历0次冒泡才停止,其中exchange是判断是不是有序的,如果有序直接退出冒泡排序,最坏的打算就是要经历最多次冒泡,就是0+1+2·····+n-1,根据等差数列求和,最后经历n*(n+1)/2,最后时间复杂度是O(N^2).

3.2.6 ⽰例6

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

那这个函数呢,cnt每次*2,当cnt>n时就退出循环,

当n=2时,执⾏次数为1
当n=4时,执⾏次数为2
当n=16时,执⾏次数为4
假设执⾏次数为 x ,则 2
x = n
因此执⾏次数: x = log n

因此:func5的时间复杂度取最差情况为:
O(log n) 

注意课件中和书籍中 log2 n 、 log n 、 lg n 的表⽰
当n接近⽆穷⼤时,底数的⼤⼩对结果影响不⼤。因此,⼀般情况下不管底数是多少都可以省略不
写,即可以表⽰为 log n
不同书籍的表⽰⽅式不同,以上写法差别不⼤,我们建议使⽤ log n

3.2.7 示例7

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

递归经历1,次时间复杂度是O(1),递归n次时间复杂度就是o(N)

4. 空间复杂度

空间复杂度也是⼀个数学表达式,是对⼀个算法在运⾏过程中因为算法的需要额外临时开辟的空间。

空间复杂度也用大O渐进表示法。

4.1 空间复杂度计算⽰例

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

        一共开辟了三个空间,end,i,exchange,用大O表示法就是O(1)

4.1.2 例2

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

首先N先进入递归,然后再进入N-1的递归,当N进入N-1的递归,此时N的函数栈帧并没有销毁,并且同时又创建了一个函数栈帧,以此类推,一共创建了N个函数栈帧。空间复杂度就是O(N)

5. 常⻅复杂度对⽐

6. 复杂度算法题

. - 力扣(LeetCode)

这种每次将最后一个元素存储,然后将前面一个元素向后面移动一个,很容易想到,通过运行两个案例也是通过了,接着,我们提交一下试试,

提交却是错的,看下,我们有38个案例,通过了37个,其中有一个没有通过案例,是因为超出时间限制了,显而易见,是我们的时间超过了最大限度。

说明这个时间复杂度较大,此时我们要通过新的算法来解决这道题了,要对算法进行一下优化。

先将数组元素存储在一个新的元素,然后再将新元素赋值给旧的数组返回即可。

相关文章:

算法复杂度

1. 数据结构前⾔ 1.1数据结构 数据结构是计算机存储数据&#xff0c;组织数据的方式&#xff0c;指相互之间存在⼀种或多种特定关系的数 据元素的集合。常见的数据结构有线性表&#xff0c;树&#xff0c;图&#xff0c;哈希等。 1.2 算法 算法是一种计算过程&#xff0c;输…...

vue到出excel

安装 npm install exceljs npm install file-saver<template><button click"dade66">导出 66</button> </template><script> import ExcelJS from exceljs; import { saveAs } from file-saver;export default {data() {return {data…...

【延时队列的实现方式】

文章目录 延时队列JDK自带的延时队列实现Redis实现延迟队列RabbitMQ 延时队列 延时队列 延时队列是一种特殊类型的队列&#xff0c;它允许元素在特定时间间隔后才能被处理。这种队列在处理具有延迟需求的任务时非常有用&#xff0c;例如定时任务、事件驱动系统等 延时队列在项…...

Fyne ( go跨平台GUI )中文文档- 扩展Fyne (七)

本文档注意参考官网(developer.fyne.io/) 编写, 只保留基本用法 go代码展示为Go 1.16 及更高版本, ide为goland2021.2 这是一个系列文章&#xff1a; Fyne ( go跨平台GUI )中文文档-入门(一)-CSDN博客 Fyne ( go跨平台GUI )中文文档-Fyne总览(二)-CSDN博客 Fyne ( go跨平台GUI…...

Qt (19)【Qt 线程安全 | 互斥锁QMutex QMutexLocker | 条件变量 | 信号量】

阅读导航 引言一、互斥锁1. QMutex&#xff08;1&#xff09;基本概念&#xff08;2&#xff09;使用示例基本需求⭕thread.h⭕thread.cpp⭕widget.h⭕widget.cpp 2. QMutexLocker&#xff08;1&#xff09;基本概念&#xff08;2&#xff09;使用示例 3. QReadWriteLocker、QR…...

Java语法-类和对象(上)

1. 面向对象的初步认识 1.1 什么是面向对象 概念: Java是一门纯面向对象的语言(Object Oriented Program&#xff0c;简称OOP)&#xff0c;在面向对象的世界里&#xff0c;一切皆为对象。 1.2 面向对象VS面向过程 如:洗衣服 面向过程: 注重的是洗衣服的过程,少了一个环节也不…...

Presto如何配置资源队列或资源组

Presto的任务队列配置主要涉及到查询队列和资源组的配置&#xff0c;这些配置通常用于管理Presto集群中的查询执行和资源分配。但是注意这两个东西是共存&#xff0c;互补的关系&#xff0c;并不需要纠结那种配置方式更加出色 一、查询队列配置 Presto的查询队列配置主要通过…...

828华为云征文|使用Flexus X实例集成ES搜索引擎

目录 一、应用场景 1.1 Flexus X实例概述 1.2 ES搜索引擎 二、安装相关服务 2.1 安装Elasticsearch7.17.0 2.2 安装kibana7.17.0 三、开通安全组规则 四、整体感受 4.1 Flexus X实例 4.2 使用感觉 一、应用场景 1.1 Flexus X实例概述 Flexus X实例是华为云推出的一款…...

【设计模式-访问者模式】

定义 访问者模式&#xff08;Visitor Pattern&#xff09;是一种行为型设计模式&#xff0c;允许你在不修改已有类的情况下向这些类添加新的功能或行为。它通过将操作的执行逻辑从对象的类中分离出来&#xff0c;使得你可以在保持类的封闭性&#xff08;符合开闭原则&#xff…...

一元运算符(自增自减)

一、一元运算符 一元运算符&#xff0c;只需要一个操作数 1. 正号 正号不会对数字产生任何影响 2.-负号 负号可以对数字进行负号的取反 对于非Number的值&#xff0c;会将先转换为Number&#xff0c;在进行运算: 可以对一个其他的数据类型使用&#xff0c;来将其转换为n…...

gitlab/极狐-离线包下载地址

如果想要使用Gitlab/极狐进行数据的恢复&#xff0c;只能使用相同版本或者相近版本的安装包&#xff0c;因此有时候需要到它的官网上下载对应版本的安装包&#xff0c;以下是我收集到的对应地址的下载路径&#xff1a; Gitlab Gitlab离线库&#xff0c; https://packages.gitl…...

C++——输入三个整数,按照由小到大的顺序输出。用指针方法处理。

没注释的源代码 #include <iostream> using namespace std; void swap(int *m,int *n); int main() { int a,b,c; int *p1,*p2,*p3; cout<<"请输入三个整数&#xff1a;"<<endl; cin>>a>>b>>c; p1&a;p2&b;p3&c;…...

【Java8 重要特性】Lambda 表达式

文章目录 Lambda函数式接口Lambda 规则规范简化过程改写 Arrays.setAll()改写 Arrays.sort() forEach循环 list 集合循环 list 集合并输出对象信息循环 Map 集合 方法引用和构造器引用方法引用构造器引用 Lambda Lambda是一个匿名函数&#xff0c;我们可以将Lambda表达式理解为…...

word2vec--CBOW与Skip-Gram 两种模型

Word2Vec 是一种流行的用于生成词嵌入&#xff08;Word Embeddings&#xff09;的无监督学习模型&#xff0c;它由 Google 的一个团队在 2013 年提出。它的主要目的是将单词映射到一个连续的向量空间&#xff0c;使得语义相似的单词在这个空间中靠得更近。 Word2Vec 有两种主要…...

iOS六大设计原则设计模式

六大设计原则&#xff1a; 一、单一职责原则 一个类或者模块只负责完成一个职责或者功能。 类似于&#xff1a;UIView 和 CALayer 二、开放封闭原则 对扩展开放&#xff0c;对修改封闭。 我们要尽量通过扩展软件实体来解决需求变化&#xff0c;而不是通过修改已有的代码来…...

nacos 集群搭建

主机准备 IProle192.168.142.155slave02192.168.142.156slave192.168.142.157master 三台主机上分别构建 mysql 镜像 FROM mysql:8.0.31 ADD https://raw.githubusercontent.com/alibaba/nacos/develop/distribution/conf/mysql-schema.sql /docker-entrypoint-initdb.d/nac…...

STM32快速复习(十二)FLASH闪存的读写

文章目录 一、FLASH是什么&#xff1f;FLASH的结构&#xff1f;二、使用步骤1.标准库函数2.示例函数 总结 一、FLASH是什么&#xff1f;FLASH的结构&#xff1f; 1、FLASH简介 &#xff08;1&#xff09;STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分&…...

漏洞扫描工具使用

首先把补丁的两个文件复制下来替换原文件 找到C:\ProgramData\Acunetix\shared\license然后替换 然后打开漏扫工具并刷新页面 然后添加要扫描的网站 等他扫描完成 扫描完成就可以生成报告了 一共五十多页的报告...

C++ | Leetcode C++题解之第424题替换后的最长重复字符

题目&#xff1a; 题解&#xff1a; class Solution { public:int characterReplacement(string s, int k) {vector<int> num(26);int n s.length();int maxn 0;int left 0, right 0;while (right < n) {num[s[right] - A];maxn max(maxn, num[s[right] - A]);i…...

利士策分享,动摇时刻的自我救赎

利士策分享&#xff0c;动摇时刻的自我救赎 在人生的长河中&#xff0c;我们每个人都会面临各种挑战与抉择&#xff0c; 那些让人心生动摇的瞬间&#xff0c;如同夜空中偶尔掠过的乌云&#xff0c;遮蔽了前行的星光。 但正是这些动摇&#xff0c;构成了我们成长的轨迹&#x…...

Android Wi-Fi 连接失败日志分析

1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分&#xff1a; 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析&#xff1a; CTR…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目&#xff0c;所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

渗透实战PortSwigger靶场:lab13存储型DOM XSS详解

进来是需要留言的&#xff0c;先用做简单的 html 标签测试 发现面的</h1>不见了 数据包中找到了一个loadCommentsWithVulnerableEscapeHtml.js 他是把用户输入的<>进行 html 编码&#xff0c;输入的<>当成字符串处理回显到页面中&#xff0c;看来只是把用户输…...

恶补电源:1.电桥

一、元器件的选择 搜索并选择电桥&#xff0c;再multisim中选择FWB&#xff0c;就有各种型号的电桥: 电桥是用来干嘛的呢&#xff1f; 它是一个由四个二极管搭成的“桥梁”形状的电路&#xff0c;用来把交流电&#xff08;AC&#xff09;变成直流电&#xff08;DC&#xff09;。…...

算术操作符与类型转换:从基础到精通

目录 前言&#xff1a;从基础到实践——探索运算符与类型转换的奥秘 算术操作符超级详解 算术操作符&#xff1a;、-、*、/、% 赋值操作符&#xff1a;和复合赋值 单⽬操作符&#xff1a;、--、、- 前言&#xff1a;从基础到实践——探索运算符与类型转换的奥秘 在先前的文…...

《信号与系统》第 6 章 信号与系统的时域和频域特性

目录 6.0 引言 6.1 傅里叶变换的模和相位表示 6.2 线性时不变系统频率响应的模和相位表示 6.2.1 线性与非线性相位 6.2.2 群时延 6.2.3 对数模和相位图 6.3 理想频率选择性滤波器的时域特性 6.4 非理想滤波器的时域和频域特性讨论 6.5 一阶与二阶连续时间系统 6.5.1 …...