
个人主页 : 流年如梦
文章目录
- 一.数据结构与算法基础
- 二.算法效率与复杂度概念
- 三.时间复杂度
-
- 3.1定义
- 3.2大O渐进表示法
- 3.3最好、最坏、平均情况
- 3.4举例
-
- [3.4.1 双层循环( O(N²) )](#3.4.1 双层循环( O(N²) ))
- [3.4.2 单层循环( O(N) )](#3.4.2 单层循环( O(N) ))
- [3.4.3 两个独立变量( O(M+N) )](#3.4.3 两个独立变量( O(M+N) ))
- [3.4.4 常数次( O(1) )](#3.4.4 常数次( O(1) ))
- [3.4.5 查找字符( O(N) )](#3.4.5 查找字符( O(N) ))
- [3.4.6 冒泡排序( O(N²) 或 O(N) )](#3.4.6 冒泡排序( O(N²) 或 O(N) ))
- [3.4.7 倍数增长( O(logN) )](#3.4.7 倍数增长( O(logN) ))
- [3.4.8 阶乘递归( O(N) )](#3.4.8 阶乘递归( O(N) ))
- 四.空间复杂度
- 五.常见复杂度对比
- [六.复杂度算法题 --> 旋转数组](#六.复杂度算法题 --> 旋转数组)
-
- [6.1方案一 --> 逐次移动(暴力美学)](#6.1方案一 --> 逐次移动(暴力美学))
- [6.2方案二 --> 创建新的数组](#6.2方案二 --> 创建新的数组)
- [6.3方案三 --> 三次逆置(最优方案)](#6.3方案三 --> 三次逆置(最优方案))
- 🎯总结
- ⚠️易错点
Ladies and gentlemen,本篇文章主要学的是 时间复杂度、空间复杂度、大 O 表示法、复杂度计算与常见复杂度对比 ;全程高能,不容错过!!!
前言
算法复杂度是衡量算法快慢与耗内存 的核心标准。不计算精确时间与空间,而是用大O渐进表示法估算增长趋势,用来在编码前就判断算法优劣,写出高效代码
一.数据结构与算法基础
数据结构 :
数据结构是计算机存储、组织数据的方式 ,是数据元素之间的关系集合;常见的有顺序表、链表、栈、队列、二叉树、哈希表等
算法 :
算法是一系列计算步骤 ,把输入转化为输出(为了效率高、资源省、逻辑清晰)
重要性:写出高效程序的基础;决定程序在大数据量下是否能跑;对今后的笔试和面试有着重要作用
二.算法效率与复杂度概念
衡量算法好坏主要看时间复杂度和空间复杂度:
- 时间复杂度 --> 衡量算法
运行快慢- 空间复杂度 --> 衡量算法
额外占用内存
三.时间复杂度
3.1定义
时间复杂度是描述算法执行次数与数据规模N 的函数关系,用大O表示法表示
不算真实运行时间(受机器或编译器影响),只算执行次数的增长趋势
3.2大O渐进表示法
- 只保留最高阶项
- 最高阶系数去掉
- 常数复杂度统一写
O(1)
例如后面举例的双层循环:
其中执行次数为T(N) = N²+2N+10,根据大O渐进表示法 我们得知它的时间复杂度为O(N²)
3.3最好、最坏、平均情况
- 最好情况:最少执行次数(下界)
- 最坏情况:最多执行次数(上界)
- 平均情况:期望次数
注意❗ :复杂度默认取最坏情况
3.4举例
3.4.1 双层循环( O(N²) )
c
void Func1(int N)
{
int count = 0;
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
count++;
for (int k = 0; k < 2*N; k++)
count++;
int M = 10;
while (M--) count++;
}
🧐分析 :执行次数为T(N) =N²+2N+10,所以时间复杂度为O(N²)(大O渐进表示法)
3.4.2 单层循环( O(N) )
c
void Func2(int N)
{
for (int k = 0; k < 2*N; k++)
count++;
while (10--) count++;
}
🧐分析 :T(N)=2N+10,时间复杂度为O(N)(大O渐进表示法)
3.4.3 两个独立变量( O(M+N) )
c
void Func3(int N, int M)
{
for (int k=0; k<M; k++);
for (int k=0; k<N; k++);
}
🧐分析 :T(N)=M+N,所以时间复杂度为O(M+N)
3.4.4 常数次( O(1) )
c
void Func4(int N)
{
for (int k=0; k<100; k++);
}
🧐分析 :执行次数固定,时间复杂度为O(1)
3.4.5 查找字符( O(N) )
c
const char* strchr(const char* str, int c)
{
while(*str && *str!=c) str++;
return str;
}
🧐分析 :最好情况时时间复杂度为O(1);最坏情况与平均情况的时间复杂度一样,为O(N)
3.4.6 冒泡排序( O(N²) 或 O(N) )
c
void BubbleSort(int* a, int n)
{
for (int end=n; end>0; end--)
{
int exchange=0;
for (int i=1; i<end; i++)
{
if (a[i-1]>a[i])
{
swap(a+i-1,a+i);
exchange=1;
}
}
if(exchange==0) break;
}
}
🧐分析 :分两种情况,如果是乱序 (即最坏情况),则时间复杂度为O(N²);如果是已排序 (即最好情况),则时间复杂度为O(N),一遍就行
3.4.7 倍数增长( O(logN) )
c
void func5(int n)
{
int cnt=1;
while(cnt < n)
cnt *= 2;
}
🧐分析 :其中执行次数 x:2ˣ=N --> x=log₂N ,所以时间复杂度为O(logN)
3.4.8 阶乘递归( O(N) )
c
long long Fac(size_t N)
{
if(N==0) return 1;
return Fac(N-1)*N;
}
🧐分析 :递归N次,时间复杂度为O(N)
四.空间复杂度
4.1定义
空间复杂度衡量算法额外开辟的临时空间 ,不算输入输出本身占用的空间,同样与时间复杂度使用大O表示法
4.2举例
4.2.1 冒泡排序
c
void BubbleSort(...)
{
int exchange;
}
🧐分析 :因为只开辟常数个变量,所以空间复杂度为O(1)
4.2.2 阶乘递归
c
long long Fac(size_t N)
{
if(N==0) return 1;
return Fac(N-1)*N;
}
🧐分析 :因为递归调用N层栈帧,所以空间复杂度为O(N)
五.常见复杂度对比
如下表格👇:
| 从快到慢依次为 | 复杂度 |
|---|---|
| 常数 | O(1) |
| 对数 | O(logN) |
| 线性 | O(N) |
| 线性对数 | O(NlogN) |
| 平方 | O(N²) |
| 立方 | O(N³) |
| 指数 | O(2ⁿ) |
| 阶乘 | O(N!) |
下面为时间复杂度对比曲线图 👇:

六.复杂度算法题 --> 旋转数组
转跳力扣👉LeetCode 189:旋转数组
原题 :

6.1方案一 --> 逐次移动(暴力美学)
c
void rotate(int* nums, int len, int k)
{
while(k--)
{
int end = nums[len-1];
for(int i=len-1; i>0; i--)
nums[i] = nums[i-1];
nums[0] = end;
}
}
提交结果 :

🧐分析 :时间复杂度为O(N×K)即O(N²),空间复杂度为O(1);但缺点是数据量大超时
6.2方案二 --> 创建新的数组
c
void rotate(int* nums, int len, int k)
{
int* tmp = (int*)malloc(len*sizeof(int));
for(int i=0; i<len; i++)
tmp[(i+k)%len] = nums[i];
for(int i=0; i<len; i++)
nums[i] = tmp[i];
free(tmp);
}
🧐分析 :时间复杂度为O(N),空间复杂度为O(N);相对于思路一它不会因为数据量大超时,可行
6.3方案三 --> 三次逆置(最优方案)
c
void reverse(int* nums, int begin, int end)
{
while(begin < end)
{
int t = nums[begin];
nums[begin] = nums[end];
nums[end] = t;
begin++;
end--;
}
}
void rotate(int* nums, int len, int k)
{
k %= len;
reverse(nums, 0, len-k-1);
reverse(nums, len-k, len-1);
reverse(nums, 0, len-1);
}
🧐分析 :时间复杂度为O(N),空间复杂度为O(1)
🎯总结
- 复杂度衡量时间快慢、空间大小
- 时间复杂度看执行次数 ,空间复杂度看额外开辟空间
- 统一用大O渐进表示法,只看最高阶
- 算法默认取最坏复杂度
- 复杂度从优到劣 :
O(1)<O(logN)<O(N)<O(NlogN)<O(N²)... - 旋转数组最优:三次逆置
O(N)时间 +O(1)空间
⚠️易错点
- 计算复杂度时保留低阶项或系数
- 递归复杂度不会算(看递归深度)
logN复杂度判断错误- 混淆时间或者空间复杂度
- 暴力算法超时,不会优化
👀 关注 我们一路同行,从入门到大师,慢慢沉淀、稳步成长
❤️ 点赞 鼓励原创,让优质内容被更多人看见
⭐ 收藏 收好核心知识点与实战技巧,需要时随时查阅
💬 评论 分享你的疑问或踩坑经历,一起交流避坑、共同进步