LeetCode 时间复杂度和空间复杂度粗略计算

server/2024/12/29 12:30:19/

#创作灵感#

刷LeetCode时需要关注的两点:时间复杂度和空间复杂度。

时间复杂度:程序的运行时消耗的时间

时间复杂度是一个函数,他定性描述了算法的运行时间。

算法导论》给出的解释是: O用来表示上界,当用他作为算法在最坏情况下运行时间的上界时,就是对任意数据输入的运行时间的上界。

插入排序时间复杂度是O(n^2)。在数据有序的情况下,插入排序的时间复杂度是O(n),在数据逆序的情况下是O(n^2),即最差情况下是O(n^2)。

 快速排序的时间复杂度是O(logn),但是在数据有序的情况下,快速排序算法时间复杂度是O(n^2),所以从O的定义来书,快速排序的时间复杂度应该是O(n^2), 但是我们依然说快速排序时间复杂度是O(logn),这就是业内的一个默认规定,这里的O就是一般情况,而不是严格意义上的上界。

空间复杂度:程序运行时占用的内存空间大小

空间复杂度(Space Complexity)是对一个算法在运行过程中占用的内存空间大小的度量,基于空间复杂度可以预先估计程序运行时需要多少内存。

空间复杂度不考虑程序(比如可执行文件)的大小,只考虑程序运行时占用的内存大小。空间复杂度不可以准确计算出程序运行时占用的内存值,因为很多因素会影响程序真正使用的内存大小,比如编译器的内存对齐方式(内存对齐、非内存对齐),编程语言容器的底层实现都会影响程序内存的开销。所以空间复杂度仅仅是大致评估程序内存使用情况。

内存对齐方式:CPU读取内存时不是一次读取单个字节,而是按照块来读取,块的大小可以是2,4,8,16字节,具体读取多少取决于硬件。

假设CPU把内存划分为4字节大小的块,要读取一份4字节大小的int32型数据,对比下两种内存对齐方式的不同(char占1字节,int32 占4字节):

  •  内存对齐:只需要一次寻址即可

 1字节的char占用4字节的内存空间,空了3字节的内存地址,int数据从地址4开始,此时直接读取4,5,6,7处的4字节数据即可。

  • 非内存对齐:需要两次寻址,外加一次合并

char数据和int32数据挨在一起,该int32数据从地址1开始,CPU读取这个int32数据需要一下步骤:

1. CPU读取0,1,2,3处的4字节数据

2. CPU读取4,5,6,7处的4字节数据

3. 合并地址1,2,3,4处后的4字节的数据才是背刺操作需要的int32数据。

以下三种不同的例子描述下空间复杂度和时间复杂度。

求斐波那契数时间复杂度空间复杂度
非递归算法(利用迭代计算,版本1)O(n)O(1)
递归算法(版本2)O(2^n)O(n)
优化递归算法(版本3)O(n)O(n)

递归算法的空间复杂度计算公式:每次递归的空间复杂度 * 递归深度

递归深度: 因为每次递归所需的空间都被压到栈里面,一次递归结束后,当前递归的数据会从栈中移除(弹出去),所以栈的最大长度(时间复杂度为O(n))就是递归的深度。

每次递归的空间复杂度在递归算法中基本上是一致的,所需要的空间是一个常量,并不会随着n的变化而变化,所以每次递归的空间复杂度是O(1).

PS:版本二中的Fibonacci(second, first + second, n-1);会导致时间复杂度变成O(n^2)

// 版本1-利用 迭代 计算斐波那契
int Fibonacci(int n)
{if (n <= 0){throw new ArgumentException("Input must be a non-negative integer.");}else if (n == 1){return 0;}else if (n == 2){return 1;}int a = 0; // F(0)int b = 1; // F(1)int fib = 0;for (int i = 3; i <= n; i++){fib = a + b;a = b;b = fib;}return fib;
}// 版本2-利用 常规递归 计算斐波那契
int Fibonacci(int n)
{if (n <= 0) return 0;if (n == 1) return 1;return Fibonacci(n - 1) + Fibonacci(n - 2);
}// 版本3-利用 优化后的递归 计算斐波那契
int Fibonacci(int first, int second, int n)
{if (n <= 0) return 0;if (n < 3) return 1;else if (n == 3) return first + second;else{return Fibonacci(second, first + second, n-1);}}

二分查找的时间复杂度和空间复杂度都是O(logn).

递归函数传递的数组参数是首元素地址而不是整个数组,也就是说每次递归都公用一块地址空间,所以每次递归的空间复杂度是一个常数O(1)。二分查找递归的深度是logn,递归深度就是调用栈的长度,那么二分查找的空间复杂度即 O(1*logn)=O(logn).

int BinarySearch(int arr[], int l, int r, int x)
{if (r >= 1){int mid = l + (r - 1) / 2;if (arr[mid] == x){return mid;}if (arr[mid] > x) {return BinarySearch(arr[], l, mid - 1, x);}else{return BinarySearch(arr[], mid + 1, r, x);}}return -1;// 未找到
}


http://www.ppmy.cn/server/153829.html

相关文章

LDR6020在iPad一体式键盘的创新应用

随着移动办公与学习的普及&#xff0c;iPad凭借其强大的性能和便携性&#xff0c;成为越来越多用户的首选设备。然而&#xff0c;随着任务复杂性的提升&#xff0c;单一的触控操作已难以满足高效、精准的需求。因此&#xff0c;一款集成了高效充电与数据传输功能的iPad一体式键…

基于submitit实现Python函数的集群计算

一、项目介绍 Submitit是一款轻量级工具&#xff0c;旨在简化Python函数在Slurm集群上的提交过程。它不仅提供了对作业结果、日志文件等的无缝访问&#xff0c;更让开发者能够在本地执行与Slurm集群间切换自如&#xff0c;极大地提高了代码的可移植性和灵活性。 Slurm作为一种…

【从零开始入门unity游戏开发之——C#篇29】C#泛型(T)和 泛型约束

文章目录 一、泛型1、泛型是什么2、泛型分类2.1. **泛型类和泛型接口**2.2. **泛型方法** 3、泛型类和接口3.1 泛型类示例&#xff1a;3.2 泛型接口示例&#xff1a;3.3 泛型类接受多个类型参数&#xff1a; 4、泛型方法4.1. **普通类中的泛型方法**4.2. **泛型类中的泛型方法*…

List详解

List详解 在Java中&#xff0c;List是一个接口&#xff0c;它继承自Collection接口。List接口为数据的有序集合提供了操作接口&#xff0c;其中可以包含重复的元素。这个接口的实现类以特定的方式存储元素&#xff0c;允许元素根据索引进行访问&#xff0c;同时还支持通过迭代…

【分布式文件存储系统Minio】2024.12保姆级教程

文章目录 1.介绍1.分布式文件系统2.基本概念 2.环境搭建1.访问网址2.账号密码都是minioadmin3.创建一个桶4.**Docker安装miniomc突破7天限制**1.拉取镜像2.运行容器3.进行配置1.格式2.具体配置 4.查看桶5.给桶开放权限 3.搭建minio模块1.创建一个oss模块1.在sun-common下创建2.…

网络安全的学习方向和路线是怎么样的?

最近有同学问我&#xff0c;网络安全的学习路线是怎么样的&#xff1f; 废话不多说&#xff0c;先上一张图镇楼&#xff0c;看看网络安全有哪些方向&#xff0c;它们之间有什么关系和区别&#xff0c;各自需要学习哪些东西。 在这个圈子技术门类中&#xff0c;工作岗位主要有以…

Python小括号( )、中括号[ ]和大括号{}代表什么

python语言最常见的括号有三种&#xff0c;分别是&#xff1a;小括号( )、中括号[ ]和大括号也叫做花括号{ }&#xff0c;分别用来代表不同的python基本内置数据类型。 小括号&#xff08;&#xff09;&#xff1a;struct结构体&#xff0c;但不能改值 python中的小括号( )&am…

VBA技术资料MF243:利用第三方软件复制PDF数据到EXCEL

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…