设计一个算法,一定要考虑到它的复杂度(空间、时间),那么,接下来,我们一步步来学习怎样分析一个算法的复杂度。
一、数据规模
首先,我们要清楚设计这个算法是要处理什么规模的数据的,根据处理的数据的规模,从而设计出适合的算法。
通常,如果要想在 1s 之内解决问题:
- O(n^2) 的算法可处理约 10^4 级别的数据
- O(n) 的算法可处理约 10^8 级别的数据
- O(nlogn) 的算法可处理约 10^7 级别的数据
不过在实际情况中,保险起见,可以对数量级低估一点,除以 10 或者 除以 2,这样就比较保险了。
二、空间复杂度
常见的空间复杂度就不解释了,需要说明的是一种比较特殊的情况。
递归是比较常见的一种算法思路,但递归调用是有空间代价的,因为计算机要把递归之前的数据压入栈中,会占用一定的空间,这点我们需要特别注意。
空间复杂度 O(1)
public static int sum1(int n) {
int ret = 0;
for (int i = 0; i <= n; i++) {
ret += i;
}
return ret;
}
这是一个简单求和的一个函数,我们只开了一个 ret 存放返回结果,和一个索引 i 的值,所以空间复杂度就是 O(n) ,不过我们也可以用递归来写,但是这样空间复杂度就变了。
空间复杂度 O(n)
public static int sum2(int n) {
if (n == 0)
return 0;
return n + sum2(n - 1);
}
这是因为在计算从 0 到 n 这些数的和,需要递归调用的深度是 n,栈中需要装载 n 个状态,也就是空间复杂度为 O(n)。
因此,在设计算法时,如果用到了递归,需要小心,不要让你的递归看起来聪明,但实际上性能却很差。
三、常见的时间复杂度分析
接下来,我们通过常见的一些函数来具体分析一下他们的时间复杂度。
注意,下面这些例子中,我们暂且假设输入都是合法输入,这样方便我们突出重点,但是在实际的算法设计中,是需要考虑到合法输入、边界条件等等信息的。
1. O(1)
e.g. 交换
private</