时间复杂度和空间复杂度

丛结果上看,我们希望我们的程序,占用低,速度快。怎么办呢,上更强的cpu,更大的内存,当然可以实现,但我们希望在同等规模的计算下,同时在相同的硬件配置下,占用低,速度快,就必须优化算法。复杂度分析就是用来衡量算法的好坏的。

对于空间复杂度,由于现在存储技术的发展,很容易有大内存,故主要优化时间复杂度。

一. 时间复杂度

时间复杂度描述算法中基本操作数量随输入规模 n 的增长趋势。

for i in range(n):
    for j in range(i):
        a += 1

我们可以看到 a+=1 运行了1一直加到n次,由等差数列公式n(n-1)/2,n小了,时间复杂度没意义,大了才有意义,取极限,就是O(n^2)

复杂度示例算法说明
O(1)数组随机访问、变量交换常数时间操作,与输入规模无关,最快
O(log n)二分查找、平衡二叉树查找每次将问题规模减半,增长极慢
O(n)顺序遍历、线性查找操作次数与输入规模成正比
O(n log n)归并排序、快速排序、堆排序高效的通用排序级别,常见于分治算法
O(n²)冒泡排序、选择排序、插入排序双重循环,适合小规模数据
O(n³)Floyd 全源最短路、三重循环矩阵运算三重嵌套循环,增长速度快
O(2ⁿ)斐波那契递归、子集枚举指数爆炸,每增加一个元素都使运算量翻倍
O(n!)全排列、旅行商问题(TSP)复杂度最高,几乎无法处理大规模输入
O(√n)判断素数(试除法)随着 n 增大增长缓慢,常见于优化性算法
O(n² log n)多维归并排序、高维计算几何算法比平方略高,常见于嵌套分治问题

判断时间复杂度到底是O几,只需要有极限意识,到底是谁在发挥作用即可。最古朴的还是计算出有多少次,然后取极限。

for (int i = 0; i < n; i++)
    for (int j = n; j > 0; j /= 2)
        // 常数操作

O(n log n)
void f(int n) {
    if (n == 0) return;
    f(n - 1);
    f(n - 1);
}


O(2^n)
void permute(int n) {
    if (n == 0) return;
    for (int i = 0; i < n; i++)
        permute(n - 1);
}

O(n!)

注意1:关于时间复杂度,我们不能光看嵌套了多少循环,嵌套了两个循环就是O(N^2),还是要看具体的次数

void logLoop(size_t n)
{
    for (size_t i = 1; i <= n; i *= 2)
    {
        // 循环体执行 O(1)
    }
}

这个的时间复杂度只有log n。

注意2:你调用函数里面的时间复杂度也要算进去,不会因为你封装函数了,时间复杂度就下来了

void foo(char *dest, const char *src, int n)
{
    for (int i = 0; i < n; ++i)   // 循环 n 次
    {
        memcpy(dest, src, n);     // 每次拷贝 n 个字节 → O(n)
    }
}

对于时间复杂度,有最好的情况,最坏的情况,和平均情况。我们一般考虑最坏的情况,因为只有这样,才能对最坏的输入有抵抗力。假如时间复杂度既跟M相关,又跟N相关,时间复杂度为O(MN),这时也是取影响最大的那个O(M^2)或O(N^2)

二.空间复杂度

空间复杂度描述的是:算法在运行过程中,除输入数据本身外,所需的额外辅助存储空间随问题规模 n 的增长关系。

注意空间复杂度是针对额外存储空间的,不是说数有多少变量,有多少数组。

O(1):这个是有限个自变量

O(N):一维数组

O(N*N):二维数组

long long Fib(size_t N)
{
    if(N < 3)
        return 1;
    return Fib(N-1) + Fib(N-2);
}

只创建了N个函数栈帧,所以,空间复杂度是O(N).

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值