时间复杂度

245 阅读3分钟

时间复杂度

一、什么是时间复杂度?

时间维度:是指执行当前算法所消耗的时间,我们通常用「时间复杂度」来描述。

二、常见的时间复杂度量级有:

  • 常数阶O(1)
  • 对数阶O(logN)
  • 线性阶O(n)
  • 线性对数阶O(nlogN)
  • 平方阶O(n²)
  • 立方阶O(n³)
  • K次方阶O(n^k)
  • 指数阶(2^n)

上面从上至下依次的时间复杂度越来越大,执行的效率越来越低。

  1. 常数阶O(1) 无论代码执行了多少行,只要是没有循环等复杂结构,那这个代码的时间复杂度就都是O(1)

  2. 对数阶O(logN)

还是先来看代码:

int i = 1;
while(i<n)
{
    i = i * 2;
}

从上面代码可以看到,在while循环里面,每次都将 i 乘以 2,乘完之后,i 距离 n 就越来越近了。我们试着求解一下,假设循环x次之后,i 就大于 2 了,此时这个循环就退出了,也就是说 2 的 x 次方等于 n,那么 x = log2^n
也就是说当循环 log2^n 次以后,这个代码就结束了。因此这个代码的时间复杂度为:O(logn)

  1. 线性阶O(n)
for(i=1; i<=n; ++i)
{
   j = i;
   j++;
}

这段代码,for循环里面的代码会执行n遍,因此它消耗的时间是随着n的变化而变化的,因此这类代码都可以用O(n)来表示它的时间复杂度。 4. 线性对数阶O(nlogN)

线性对数阶O(nlogN) 其实非常容易理解,将时间复杂度为O(logn)的代码循环N遍的话,那么它的时间复杂度就是 n * O(logN),也就是了O(nlogN)。

就拿上面的代码加一点修改来举例:

for(m=1; m<n; m++)
{
    i = 1;
    while(i<n)
    {
        i = i * 2;
    }
}
  1. 平方阶O(n²)

平方阶O(n²) 就更容易理解了,如果把 O(n) 的代码再嵌套循环一遍,它的时间复杂度就是 O(n²) 了。
举例:

for(x=1; i<=n; x++)
{
   for(i=1; i<=n; i++)
    {
       j = i;
       j++;
    }
}

这段代码其实就是嵌套了2层n循环,它的时间复杂度就是 O(n*n),即 O(n²)
如果将其中一层循环的n改成m,即:

for(x=1; i<=m; x++)
{
   for(i=1; i<=n; i++)
    {
       j = i;
       j++;
    }
}

那它的时间复杂度就变成了 O(m*n)

  1. 立方阶O(n³)K次方阶O(n^k)

对比 O(n²) 即嵌套了3层N循环以及k层N循环

三、以递归算法实例探究时间复杂度

以递归算法为例,对递归算法的时间复杂度做进一步的分析

经典例题:求x的n次方

方法一:for循环

def fun1(x,n):
    ans=1
    for i in range(n):
        ans=ans*x
    return ans

时间复杂度为O(n)

还有没有更好的方法呢?

方法二:递归

int digui2(int x, int n) {
    if (n == 0) {
        return 1; // return 1 同样是因为0次方是等于1的
    }
    return digui2(x, n - 1) * x;
}

那么这份代码的时间复杂度是多少?

递归算法的时间复杂度本质上是要看: 递归的次数 * 每次递归中的操作次数

每次n-1,递归了n次 时间复杂度是O(n),每次进行了一个乘法操作,乘法操作的时间复杂度一个常数项O(1)

所以这份代码的时间复杂度是 n * 1 = O(n)

int digui3(int x, int n) {
    if (n == 0) {
        return 1;
    }
    if (n % 2 == 1) {
        return digui3(x, n/2) * digui3(x, n/2)*x;
    }
    return digui3(x, n/2) * digui3(x, n/2);
}

优化后的递归算法代码

int digui4(int x, int n) {
    if (n == 0) {
        return 1;
    }
    int t = digui4(x, n/2);// 这里相对于digui3,是把这个递归操作抽取出来
    if (n % 2 == 1) {
        return t*t*x;
    }
    return t*t;
}

参考文献: blog.51cto.com/u_15069438/…