什么是算法复杂度?
你有没有遇到过这种情况:写了个程序,处理10个数据飞快,可一到1000个数据就卡得像老牛拉车?问题可能不在电脑配置,而在“算法复杂度”。
简单说,算法复杂度就是衡量一段代码“干活效率”的指标。它不看你用的是什么语言,也不管你的电脑多快,而是关注:当数据量变大时,这段代码需要花多少时间和空间。
时间复杂度:别让程序等到天荒地老
时间复杂度,描述的是程序运行时间随数据量增长的变化趋势。我们常用“大O符号”来表示,比如 O(1)、O(n)、O(n²)。
O(1) 是最理想的,意思是不管数据有多少,执行时间都差不多。就像从手机通讯录里直接拨给“老婆”,点一下就行,跟通讯录有10人还是1000人没关系。
O(n) 表示时间跟数据量成正比。比如你要在通讯录里找“张三”,就得一个个翻,联系人越多,找得越久。
来看个例子:
for (int i = 0; i < n; i++) {
System.out.println(arr[i]);
}这个循环会走 n 次,所以时间复杂度是 O(n)。
嵌套循环?小心指数级增长
如果循环里面再套循环,复杂度就容易飙升。比如下面这段代码:
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.println(arr[i][j]);
}
}外层循环跑 n 次,内层也跑 n 次,总共就是 n×n 次操作,时间复杂度变成 O(n²)。当 n=1000 时,操作次数就是100万次,机器压力立马上来。
空间复杂度:内存不是大风刮来的
除了时间,还得看空间复杂度——程序运行时占了多少内存。
比如你写了个函数,每来一个数据就 new 一个对象存起来,那内存占用就会随着数据增多线性上涨,空间复杂度就是 O(n)。
而如果只是用几个变量做计算,不管数据多大,内存开销都差不多,那就是 O(1)。
常见复杂度排名,心里要有数
以下是从“很爽”到“别碰”的常见复杂度排序:
- O(1) —— 常数级,稳如老狗
- O(log n) —— 对数级,数据翻倍,时间只加一点点(比如二分查找)
- O(n) —— 线性级,能接受
- O(n log n) —— 常见于高效排序,比如快速排序
- O(n²) —— 数据一多就慢,尽量避免嵌套循环
- O(2^n) 或 O(n!) —— 指数爆炸,除非数据极小,否则别用
举个生活例子:你点外卖,商家接单后要打包10份餐。如果是顺序打包,每份1分钟,总耗时10分钟(O(n))。但如果每打包一份都要重新核对前面所有订单,那就可能变成 O(n²),打包第10份时还要回头查9次,效率自然低。
怎么估算自己的代码?
有个土办法:看看循环怎么写的。单层循环通常是 O(n),两层嵌套一般是 O(n²)。如果有“每次砍掉一半”的逻辑,比如猜数字游戏,那就是 O(log n)。
比如你要在一堆书里找某一本,如果没排序,只能一本本翻(O(n));如果按字母排好了,就可以折半查找,快得多(O(log n))。
理解算法复杂度,不是为了背公式,而是养成一种思维习惯:写代码时多问一句——如果数据变10倍,我的程序还能扛住吗?