时间复杂度
时间复杂度的分析
- 只关注循环执行次数最多的一段代码,因为使用大O表示法,其他执行次数较少的复杂度可以忽略
- 加法法则:总复杂度等于量级最大的那段代码的复杂度
- 乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积
常见的时间复杂度示例
复杂度从低阶到高阶为:(复杂度越高阶,执行效率越低)
O(1)、O(logn)、O(n)、O(nlogn)、O(n^2)
O(1)
该时间复杂度表示代码的执行时间可以认为与输入n无关,是一个固定的值
O(logn)&O(nlogn)
o(logn)复杂度有一个很好的例子可以进行说明:
i=1
while(i<=n){
i=i*2;
}
i的值随每一次循环变化为:1,2,4,...,n
执行次数x满足:2^x=n,x=log2n
对代码进行更改:
i=1
while(i<=n){
i=i*3;
}
现在代码的执行次数变成x=log3n
以上两种都可以表示为O(logn)
O(logn)可以使用乘法法则进行理解
O(m+n)&O(m*n)
O(m+n)、O(m+n)表示复杂度随着两个输入的规模而变化。
O(n^2)
这种复杂度一般是存在两层循环的情况
最好&最坏时间复杂度
在一些代码中,每种情况下代码的执行时间不同,例如在数组中寻找一个特定的元素
在这种情况下,可以使用最好、最坏时间复杂度进行表示,这两种情况都是理想情况。
平均时间复杂度
平均复杂度是在前一种情况下更好地表示代码的复杂度。它等于代码各种可能出现的情况乘以其概率之和。平均时间复杂度也可以称为加权平均时间复杂度或者是期望时间复杂度。
均摊时间复杂度
存在如下代码
let array=[]
let count=0
insert(int val){
if(count==array.length){
int sum=0;
for(int i=0;i<array.length;i++){
sum=sum+array[i]
}
array[0]=sum
count=1;
}
array[count]=val
++count
}
代码实现了向一个数组中添加元素,如果数组已满,计算其中元素和,存放在第一个元素,再插入元素
这种情况下,在大部分时候,代码的复杂度为O(1),在小部分时候复杂度为O(n)。
实际上,因为两者具有一定的规律,所以可以将O(n)复杂度均摊到O(1)复杂度的时候,在这种情况下,连续操作下,复杂度仍为O(1)
以上的分析方法称为摊还分析法
在一般能使用摊还分析法的代码中,时间复杂度等于其最好情况时间复杂度.
其实,摊还分析就是在一定规律的操作下,将出现频率较低的高时间复杂度分摊至出现频率较高的低时间复杂度上,最后计算出的复杂度将会较低,这种复杂度也可以视为一种平均复杂度。
空间复杂度
空间复杂度分析
一般常见的空间复杂度为O(1):一个单一的存储变量,O(n):一个数组、O(n^2):一个二维数组