算法 | 时间与空间复杂度

简介: 算法 | 时间与空间复杂度

算法的效率


算法的效率主要由以下两个复杂度来评估:


时间复杂度:评估执行程序所需要的时间。可以估算出程序对处理器的使用程度


空间复杂度:评估执行程序所需要的的存储空间。可以估算出程序对计算机内存的使用程度


设计算法时,一般要先考虑系统环境,然后在权衡时间复杂度和空间复杂度,选取一个平衡点。不过,时间复杂度要比空间复杂度更容易产生问题,因此算法主要研究的也是时间复杂度,不说明的情况下,复杂度指的就是时间复杂度。


时间复杂度


下面看一个小栗子:


fun fun1(): Int {
    println("哈,我是345")
    return 0;
}
fun fun2(n: Int): Int {
    for (i in 0..n) {
        println("哈,我是345  ")
    }
    return 0
}


首先,调用一次 fun1,内部会执行两次语句,这个两次可以记做为常数


调用一次 fun 2,内部会执行 1 + (n+1)+n +n +1,也就是 3n +3次,为啥呢,如下:


1,首先 i = 1是一次。


2,i 每次会判断是否小于 n ,会执行 n+1 次。


3,i 每次循环会自增,则执行 n 次。


4,打印语句会执行 n 次


5,return 一次


最终的结果为 3n+3次


所以上面的两个函数的执行次数分别是 2 和 3n+3 次。


但是日常开发中不可能这样去数,所以根据代码执行时间和执行过程就有一个规律,也就是代码执行的时间 T(n) 和代码的执行次数 f(n) ,这个是成正比的,而且这个规律有一个公式 :

T ( n ) = O ( f ( n ) ) T(n) = O(f(n))

T(n)=O(f(n))


其中,n 是输入数据的大小或者输入数据的数量


T(n) :表示一段代码的总执行时间


f (n):表示一段代码的执行总次数


0 :表示代码的执行时间 T(n) 和执行次数 f(n) 成正比


完整的公式看着有些麻烦,我们平时的算法复杂度主要是用 0() 来表示,读作大欧表示法。


回到上面的两个例子:


第一个函数执行了三次,用复杂度表示就是 O(3)

第二个函数执行了 3n +3 次,复杂度就是 O(3n + 3)

上面的写法还是非常麻烦,如果函数的内部的执行次数是固定的,并没有变量存在,那么他的执行时间也就没有什么差别了,例如 O(3) 和 O(4) 。所以复杂度中有一个同意的简化方法,这个简化方法的估算就是我们最终的时间复杂度,简化过程如下:


如果 T(n) = 常数


那么时间复杂度可以估算为 1 ,因此 T(n) = 2 的复杂度就是 1


对于 fun1() 函数,他的执行次数是一个常数,也就是说他的数量是固定的,那么他的时间复杂度就是 O(1),就算是它内部有上万行代码,时间复杂度也是 0(1)


如果 T(n) = 常数 * n + 常数


可以直接 去掉后面的 + 常数,应为当 (常数 * n) 越来越大,后面的则是保持不变,所以后面的相当于不存在,所以可以直接省略


然后 (常数 * n) 中的常数可以估算为 1,也可以理解为去掉这个作为系数的常数,所以他的时间复杂度就是 0(n)


对于 fun2() 函数,他的执行次数是 常数 *n ,那么他的时间复杂度就是 0(n)


因此 T(n) = 3n + 3 的复杂度为 n


T(n) = 多项式(5n³ + 6666n² + 233)


对于多项式,我们只需要保留 n 的最高次项,也就是保留 n 的次方数最大的那一项,低于这个次项的直接忽略不计。因此 时间复杂度就是 0(n³)


常见的时间复杂度


O(1):常数阶


fun fun1(): Int {
    println("哈,我是345")
    println("哈,我是345")
    println("哈,我是345")
    return 0;
}


只要算法中没有循环或者递归,不管多少行代码,他的复杂度都是 0(1)


O(n):线性阶


fun fun2(n: Int): Int {
    for (i in 0..n) {
        println("哈,我是345  ")
    }
    for (i in 1..n) {
        println("哈,我是345  ")
    }
    return 0
}


虽然上面有两个循环,但是并没有嵌套,所以时间复杂度就是 0(n)


O(n²):平方阶


fun fun2(n: Int): Int {
   for (i in 0..n) {
       for (i in 1..n) {
         println("哈,我是345  ")
      }
    }
   for (i in 1..n) {
         println("哈,我是345  ")
    }
    return 0
}


O(logn):对数阶


最经典的例子就是二分查找了,每次都从剩下的一半中进行查找,这就是典型的 logn。因为循环的次数影响的主要来源就是 n / 2, 这个时间复杂度就是 O(logn)。


fun foo3(n:Int){
    for(let i = 1; i < n; i *= 2){
        console.log("一天")
    }
}


循环执行的次受到了 i *= 2 影响,乘完后距离 n 就越来越近了。该例子中:


真数,也就是 n 的大小


底数就是值变化的规律,例如这里每次循环都是 i *= 2 ,这个乘2就是规律。例如 1,2,3,4,5 这样的话,底数就是 1,每个数的规律变化都是 +1


对数可以理解为 *2 乘了多少次的次数。


所以,这个题中的 底数就是 2,对数就是 b,结果就是 n ,表达式如下:


a^b = n ,读作以 a 为底 n 的对数等于 b,也就是 2^b = n,读作以2为底n的对数。转换一下,就是 2^b = n


所以这个题就可以理解为 log2n = ?,用时间复杂度就可以表示为 O(log2n),由于时间复杂度需要去掉系数和常数所以这个时间复杂度就是 O(logn),


其他时间复杂度


image.png

以上复杂度都是由快到慢排列


2d65d23f6d4748949b924e4057485923.png


以上数据图片参自https://juejin.cn/post/6999307229752983582


空间复杂度


空间复杂度就是算法需要多少内存,占用了多少空间,常用的空间复杂度有 O(1) ,O(n) ,O(n²),


O(1)


fun fun1(): Int {
    println("哈,我是345")
    println("哈,我是345")
    println("哈,我是345")
    return 0;
}


只要不是因为算法的运行而额外的导致空间增长,内部无论多少行代码,空间复杂度都是 O(1)


O(n)


fun fun2(n: Int) {
    val list = arrayListOf<Int>()
    for (i in 0..n) {
        list.add(i)
    }
}


如上面这种,n 的数值越大,所需要分配的空间就越多,所以他的空间复杂度是 O(n) ,时间复杂度也是 O(n)


O(n²)


fun fun2(n:Int){
    var list = ArrayList<ArrayList<Int>>()
}


这种复杂度一般出现在二位数组,或者是矩阵的情况下。


最后


因为最近在刷一些算法题,恰好对这些有点陌生,所以就复习了一下。


相关文章
|
1月前
|
机器学习/深度学习 缓存 算法
Python算法设计中的时间复杂度与空间复杂度,你真的理解对了吗?
【10月更文挑战第4天】在Python编程中,算法的设计与优化至关重要,尤其在数据处理、科学计算及机器学习领域。本文探讨了评估算法性能的核心指标——时间复杂度和空间复杂度。通过详细解释两者的概念,并提供快速排序和字符串反转的示例代码,帮助读者深入理解这些概念。同时,文章还讨论了如何在实际应用中平衡时间和空间复杂度,以实现最优性能。
62 6
|
3月前
|
机器学习/深度学习 算法 程序员
读《趣学算法》:重开算法之门,时间复杂度与空间复杂度
本文是作者阅读《趣学算法》后的笔记,介绍了算法复杂度的基本概念,包括时间复杂度和空间复杂度的不同阶表示,并通过具体例子展示了如何计算和理解算法的效率。
68 2
读《趣学算法》:重开算法之门,时间复杂度与空间复杂度
|
4月前
|
机器学习/深度学习 存储 算法
颠覆认知!Python算法设计中的时间复杂度与空间复杂度,你真的理解对了吗?
【7月更文挑战第22天】在Python算法设计中,时间与空间复杂度是评估算法效能的核心。时间复杂度不仅限于大O表示法,还涵盖平均与最坏情况分析。空间复杂度虽关注额外存储,但也反映内存效率。平衡二者需视场景而定,如利用原地算法减少内存消耗,或牺牲空间加速执行。算法优化技巧,如分治与动态规划,助你在资源与速度间找寻最优解,从而高效应对大数据挑战。
48 3
|
1月前
|
存储 算法
算法的时间复杂度和空间复杂度
本文详细讨论了算法的时间复杂度和空间复杂度,包括它们的概念、计算方法和常见复杂度的对比,并通过多个实例解释了如何计算算法的时间和空间复杂度。
65 0
算法的时间复杂度和空间复杂度
|
1月前
|
机器学习/深度学习 存储 算法
【初阶数据结构】算法效率大揭秘 | 时间与空间复杂度的深度剖析
【初阶数据结构】算法效率大揭秘 | 时间与空间复杂度的深度剖析
|
2月前
|
算法 Python
震惊!Python 算法设计背后,时间复杂度与空间复杂度的惊天秘密大起底!
在 Python 算法设计中,理解并巧妙运用时间复杂度和空间复杂度的知识,是实现高效、优雅代码的必经之路。通过不断地实践和优化,我们能够在这两个因素之间找到最佳的平衡点,创造出性能卓越的程序。
40 4
|
2月前
|
缓存 算法 数据处理
时间&空间复杂度,Python 算法的双重考验!如何优雅地平衡两者,打造极致性能?
在Python算法中,时间与空间复杂度的平衡至关重要。时间复杂度反映算法执行时间随输入规模的变化趋势,空间复杂度则关注额外存储空间的需求。优秀的算法需兼顾两者,如线性搜索时间复杂度为O(n),空间复杂度为O(1);二分查找在时间效率上显著提升至O(log n),空间复杂度保持为O(1);动态规划通过牺牲O(n)空间换取O(n)时间内的高效计算。实际应用中,需根据具体需求权衡,如实时数据处理重视时间效率,而嵌入式系统更关注空间节约。通过不断优化,我们能在Python中找到最佳平衡点,实现高性能程序。
66 3
|
1月前
|
算法 C语言
深入理解算法效率:时间复杂度与空间复杂度
深入理解算法效率:时间复杂度与空间复杂度
|
3月前
|
搜索推荐
九大排序算法时间复杂度、空间复杂度、稳定性
九大排序算法的时间复杂度、空间复杂度和稳定性,提供了对各种排序方法效率和特性的比较分析。
150 1
|
4月前
|
存储 算法 搜索推荐
深度剖析 Python 算法:时间复杂度与空间复杂度的爱恨情仇,你站哪边?
【7月更文挑战第23天】在Python算法设计中,时间复杂度与空间复杂度如影随形,反映算法效率与资源消耗。时间复杂度揭示算法随输入规模增长的计算趋势,空间复杂度关注额外存储需求。找最大值示例中,两种实现均具O(n)时间与O(1)空间复杂度,但在排序等复杂场景下,如冒泡排序与快速排序,或哈希表与二叉树查找,权衡变得关键。实时系统偏好低时间复杂度算法,存储受限环境则需关注空间效率。最佳选择依应用场景而定,掌握二者平衡,方能编写高效代码。
41 10