【时间复杂度和空间复杂度之间的故事】

news2025/1/18 17:01:53

【时间复杂度和空间复杂度之间的故事】

      • 一.前言
  • 二.时间复杂度
      • 定义
      • 时间复杂度的计算规则
      • 习题
  • 三.空间复杂度
      • 定义
      • 计算方法
      • 习题
      • 空间复杂度 O(1)
      • 空间复杂度 O(n)

本文主要讲解关于时间复杂度与空间复杂度
😀😃😁😁😇😇
在这里插入图片描述

😀😃😁😁😇😇

一.前言

时间复杂度主要衡量的是一个算法的运行速度,而空间复杂度主要衡量一个算法所需要的额外空间。在计算机发展的早期,计算机的存储容量很小,所以对空间复杂度很是在乎。但是随着计算机行业的迅速发展,计算机的存储容量已经达到了很高的程度。所以我们如今已经不需要再特别关注一个算法的空间复杂度。这就是为什么我们大多时候听到的是时间复杂度,而很少听到空间复杂度的原因。

二.时间复杂度

定义

  1. 时间复杂度就是用来方便开发者估算出程序的运行时间
  2. 我们该如何估计程序运行时间呢,我们通常会估计算法的操作单元数量,来代表程序消耗的时间,
    这里我们默认CPU的每个单元运行消耗的时间都是相同的。
  3. 假设算法的问题规模为n,那么操作单元数量便用函数f(n)来表示
  4. 随着数据规模n的增大,算法执行时间的增长率和f(n)的增长率相同,这称作为算法的渐近时间复杂度,简称时间复杂度,记为 O(f(n))
  5. 这里就要说一下这个大O,什么是大O呢,很多同学说时间复杂度的时候都知道O(n),O(n^2),但说不清什么是大O,算法导论给出的解释:大O用来表示上界的,当用它作为算法的最坏情况运行时间的上界,就是对任意数据输入的运行时间的上界。
    😀😃😁😁😇😇

时间复杂度的计算规则

  • 基本操作即只有常数项,认为其时间复杂度为O(1)
  • 顺序结构,时间复杂度按加法进行计算
  • 循环结构,时间复杂度按乘法进行计算
  • 分支结构,时间复杂度取最大值
  • 在没有特殊说明时,我们所分析的时间复杂度都是指最坏时间复杂度
  • 判断一个算法效率时,往往只需要关注操作数量的最高次项,其他次要项和常数项可以忽略

注:递归算法的时间复杂度 = 递归的次数 * 每次递归函数中的次数。

习题

例一

int result = 100; //运行程序只执行一次  
 
result ++ ;  //执行一次
 
System.out.println ("Hello!"+result);

上面算法的运行的次数的函数为f(n)=3,根据推导大O阶的规则1,每次运行程序每条语句执行一次,所以这个算法的时间复杂度仍旧是O(1),我们可以称之为常数阶。

例二

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

fun3的基本操作的执行了100次,通过推导大O阶方法知道,时间复杂度为O(1),也就是执行次数为常数。

例三

for(int i=0;i<n;i++){
 
   System.out.println(result[i]);  //执行一次
 
}

上面算法循环体中的代码执行了n次,因此时间复杂度为O(n),实际上,在for循环里面的所有时间复杂度为O(1)的语句总的时间复杂度都是O(n)。

例四

int result=1;
 
while(result<n){
 
    result=result*2; //时间复杂度为O(1)
 
}

可以看出上面的代码, result=result*2; 随着result每次乘以2后,都会越来越接近n,当result大于等于n时就会退出循环(限制条件)。

如果循环的次数为T,所以2^T=n于是T=log₂n,因此得出这个算法的时间复杂度为O(logn)。

例五

//二分查找法
int BinarySearch(int* a, int  n, int x) {
	assert(a);
	int begin = 0;
	int end = n - 1;
	
	while (begin < end) {
	
		int mid = ((end - begin) >> 1) + begin; //计算end与begin的中间值,右移1位相当于除以2
		
		if (a[mid] < x) {begin = mid - 1;}
		else if(a[mid]>x){end = mid;}
		else {return mid;}
		
	}
	
	return -1;
}

时间复杂度为:O(logN)。分析如下:

第一次查找:在长度为N的数组中查找值,取中间值进行比较
第二次查找:在长度为N/2的数组中查找值,取中间值进行比较
第三次查找:在长度为N/(2^2)的数组中查找值,取中间值进行比较
第logN次查找:在长度为N/(2^logN)的数组中查找值,即在长度为1的数组中查找,无论是否找到均跳出循环,结束查找

例六

  for(int i=0;i<n;i++){       
       for(int j=0;j<n;j++){     
           System.out.println(result[i][j]);  //执行一次     
       }     
    }

这是一个循环嵌套的语句,很明显内层循环的时间复杂度在讲到线性阶时就已经得知是O(n),又经过了外层循环n次,那么这段算法的时间复杂度则为O(n²)。

例七

void fun(int n){
    int i,j,x=0;
    for(i=1;i<n;i++){
       for(j=n;j>=i+1;j--){
           x++;
       }
    }
}

在这里插入图片描述

例八

void fun(int n){
    int i=0;
    while(i*i*i<=n){
        i++;
    }
}

在这里插入图片描述
例九

// 多个复杂度组合
 
for(int i=0;i<n;i++){   
   for(int j=0;j<n;i++){ 
       System.out.println(result[i][j]);  //执行一次 
   } 
}
 
for(int i=0;i<n;i++){  
   System.out.println(result[i]);  //执行一次 
}

对于顺序执行的语句或者算法,总的时间复杂度等于其中最大的时间复杂度。所以对于以上的代码,时间复杂度为O(n²)。

例十

// 多个复杂度组合
if(flag){ 
   for(int i=0;i<n;i++){  
       for(int j=0;j<n;i++){ 
          System.out.println(result[i][j]);  //执行一次 
       } 
    } 
}else{ 
    for(int i=0;i<n;i++){   
       System.out.println(result[i]);  //执行一次 
    } 
}

对于条件判断语句,总的时间复杂度等于其中时间复杂度最大的路径的时间复杂度。所以对于以上的代码,时间复杂度为O(n²)。
在这里插入图片描述

三.空间复杂度

定义

既然时间复杂度不是用来计算程序具体耗时的,那么我也应该明白,空间复杂度也不是用来计算程序实际占用的空间的。
空间复杂度是对一个算法在运行过程中临时占用存储空间大小的一个量度,同样反映的是一个趋势,我们用 S(n) 来定义。
😀😃😁😁😇😇

计算方法

空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度。空间复杂度不是程序占用了多少字节的空间,因为这个也没太大意义,所以空间复杂度算的是变量的个数。空间复杂度计算规则基本跟时间复杂度类似,也使用大O渐进表示法。

习题

空间复杂度比较常用的有:O(1)、O(n)、O(n²),我们下面来看看:

空间复杂度 O(1)

如果算法执行所需要的临时空间不随着某个变量n的大小而变化,即此算法空间复杂度为一个常量,可表示为 O(1)

int i = 1;
int j = 2;
++i;
j++;
int m = i + j;

代码中的 i、j、m 所分配的空间都不随着处理数据量变化,因此它的空间复杂度 S(n) = O(1)

空间复杂度 O(n)

int[] m = new int[n]
for(i=1; i<=n; ++i)
{
   j = i;
   j++;
}

这段代码中,第一行new了一个数组出来,这个数据占用的大小为n,虽然有循环,但没有再分配新的空间,因此,这段代码的空间复杂度主要看第一行即可,即 S(n) = O(n).

例一

//计算冒泡排序函数的空间复杂度
void BubbleSort(int* a, int N)
{
	assert(a);
	for (int i = 0; i < N; i++)
	{
		int exchange = 0;
		for (int j = 0; j < N - 1 - i; j++)
		{
			if (a[j]>a[j + 1])
			{
				int tmp = a[j];
				a[j] = a[j + 1];
				a[j + 1] = tmp;
				exchange = 1;
			}
		}
		if (exchange == 0)
			break;
	}
}

冒泡排序函数中使用了常数个额外空间(即常数个变量),所以用大O的渐进表示法表示冒泡排序函数的空间复杂度为O(1) 。

例二

//计算阶乘递归函数的空间复杂度
long long Factorial(size_t N)
{
	return N < 2 ? N : Factorial(N - 1)*N;
}

阶乘递归函数会依次调用Factorial(N),Factorial(N-1),…,Factorial(2),Factorial(1),开辟了N个空间,所以空间复杂度为O(N) 。

注:递归算法的空间复杂度通常是递归的深度(即递归多少层)。

在这里插入图片描述

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

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

相关文章

鸿蒙ArkUI-X跨语言调用说明:平台差异化【Android、ios动态化】

动态化介绍 简介 ArkUI-X支持动态化&#xff0c;使用者可以根据自己需要动态发布跨平台内容&#xff0c;从而使跨平台部分和宿主应用进行解耦。动态化能力支持如下两个典型场景&#xff1a; 框架动态化&#xff1a;指ArkUI跨平台开发框架本身可以做到动态下发&#xff0c;即…

webpack优化构建体积示例-压缩图片:

不同的图片格式有不同的特点和用途&#xff0c;它们也需要不同的压缩算法和技术&#xff0c;也为了保证能在各个浏览器环境下能正常加载显示&#xff0c;所以需要用到多个插件 在使用imagemin-webpack-plugin来配置图片压缩时&#xff0c;你需要确保已经安装了该插件以及它可能…

GBDT调参--贝叶斯调参

随机抽特征和随机抽样本 n_estimators 是控制森林中树木的数量&#xff0c;即基评估器的数量。这个参数对随机森林模型的精确性影响是单调的&#xff0c;n_estimators越 大&#xff0c;模型的效果往往越好。但是相应的&#xff0c;任何模型都有决策边 n_estimators达到一定的程…

WPS二次开发系列:第三方应用快速接入WPS打印功能

作者持续关注 WPS二次开发专题系列&#xff0c;持续为大家带来更多有价值的WPS开发技术细节&#xff0c;如果能够帮助到您&#xff0c;请帮忙来个一键三连&#xff0c;更多问题请联系我&#xff08;QQ:250325397&#xff09; 目录 应用场景 Demo效果演示 SDK申请及初始化 SD…

Java面试八股之HashSet和TreeSet有什么区别

Java中HashSet和TreeSet有什么区别 1. 底层数据结构 HashSet: 基于哈希表&#xff08;实际上是 HashMap 的内部实现&#xff09;实现。每个元素通过其 hashCode() 方法计算出哈希码&#xff0c;并通过哈希码确定其在哈希表中的位置。这种结构使得 HashSet 在插入、删除和查找…

华为 2024 届实习校园招聘-硬件通⽤/单板开发——第六套

华为 2024 届实习校园招聘-硬件通⽤/单板开发——第六套 部分题目分享&#xff0c;完整版带答案(有答案和解析&#xff0c;答案非官方&#xff0c;未仔细校正&#xff0c;仅供参考&#xff09;&#xff08;共十套&#xff0c;每套四十题选择题&#xff09;获取&#xff08;WX:…

零基础入门篇④ 初识Python(注释、编码规范、关键字...)

Python从入门到精通系列专栏面向零基础以及需要进阶的读者倾心打造,9.9元订阅即可享受付费专栏权益,一个专栏带你吃透Python,专栏分为零基础入门篇、模块篇、网络爬虫篇、Web开发篇、办公自动化篇、数据分析篇…学习不断,持续更新,火热订阅中🔥专栏订阅地址 👉Python从…

Shiro核心深度解析文档

1. Shiro的介绍 它是一个简单易用的java安全框架,可以运行在非Web环境 1.主要提供的功能 身份认证 大多时称为登录,这是证明用户身份的行为 授权管理 访问控制的过程,即决定"谁"可以做"什么" 会话管理 管理特定于用户的会话,在非Web环境也是这样 密码…

echarts 图表tooltip扩展(适配移动端)

2024.5.16今天我学习了如何对echarts 图表tooltip进行自定义设置&#xff0c;效果如&#xff1a; 如果是日维度&#xff0c;需要展示对应的星期&#xff0c;以及用移动端去查看这个图表提示要显示在整个图表内&#xff0c;如果没有设置position会溢出图表&#xff0c;通用写法代…

数据结构与算法|算法总结|动态规划之编辑距离总结篇

啥也不说先上图&#xff01; 本节一共总结了六道题&#xff0c;个人认为作为二维dp的典型用法&#xff0c;所以归纳到了一起&#xff0c;方便对比、类比学习。 718.最长重复子序列 力扣题目链接 文章链接 两个整数数组A、B&#xff0c;返回两个数组中 公共的、长度最长的子数组…

跨域数据流动:数据提取过程中的治理与安全双轮驱动

跨域数据流动&#xff1a;数据提取过程中的治理与安全双轮驱动 随着信息技术的飞速发展&#xff0c;跨域数据流动已成为现代社会的常态。从医疗记录到金融交易&#xff0c;从社交媒体到企业运营&#xff0c;数据在各个领域之间频繁交换&#xff0c;为社会发展带来了极大的便利…

Cocktail for Mac 激活版:一站式系统优化与管理神器

Cocktail for Mac是一款专为Mac用户打造的系统优化与管理工具&#xff0c;凭借其强大的功能和简便的操作&#xff0c;赢得了广大用户的喜爱。这款软件集系统清理、修复和优化于一身&#xff0c;能够帮助用户轻松解决Mac系统中的各种问题&#xff0c;提高系统性能。 Cocktail fo…

MySQL单表查询案例演示

目录 一、创建数据库lianxi 二、选择数据库为lianxi 三、新建一个数据表grade&#xff0c;在grade表中插入数据 四、开始进行查询操作&#xff08;验证表中数据&#xff09; 1、查询1945班的成绩信息 2、查询1945班&#xff0c;语文成绩大于60小于90的成绩信息 3、查询学…

电商数据分析的介绍及应用||电商数据API接口

在这到处弥漫着电商气息的社会里&#xff0c;人们依靠电商让生活变得简单而便捷。那么作为电商数据分析师&#xff0c;我们需要在海量电商数据中揭示出隐含的、先前未知的并有潜在价值的信息和规律&#xff0c;这也要求我们具备数据洞察和汇总能力&#xff0c;运用数据挖掘模型…

Leetcode-有效的括号(带图)

20. 有效的括号 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/valid-parentheses/ 题目 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&…

git 拉取指定目录

指令方式 打开 git 自带的Git Bash 工具 以拉取github中 fastjson 的 /src/test/java/oracle/sql/ 目录为例 1.创建文件夹和git 初始化 cd D:/Program\ Files mkdir fastjson cd fastjson git init 2.设置允许克隆子目录 git config core.sparsecheckout true 3.添加远程…

【physx/wasm】在physx中添加自定义接口并重新编译wasm

目录 说在前面环境搭建编译自定义接口 说在前面 操作系统&#xff1a;windows11wsl2physx版本&#xff1a;5.3.1参考&#xff1a;physx-js-webidl (physx版本为该作者fork出的某个版本) 环境搭建 这里使用的是wsl2docker进行编译的&#xff0c;搭建步骤参考&#xff1a;WSL2 上…

深入探索Jetpack Compose:大前端式客户端开发实战

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

win10编译openssl

环境 Win10 64位 VS2022 openssl 3.3.0 nasm NASM version 2.16.01 compiled on Dec 21 2022 perl strawberry-5.38.2.2环境变量设置 perl加入到环境变量&#xff0c;略过nasm加入到环境变量vs的nmake加入到环境变量我的nmake位置如下&#xff1a; C:\Program…

【Unity Shader入门精要 第7章】基础纹理(二)

除了用于直接表示物体表面颜色&#xff0c;纹理的另外一种常见用法是用来进行凹凸映射&#xff0c;在不增加顶点的情况下&#xff0c;通过纹理来提供额外的法线信息&#xff0c;从而在视觉上增加表面凹凸细节&#xff0c;丰富渲染表现。 最常用的两种凹凸映射为法线贴图和高度…