时间复杂度和空间复杂度
时间复杂度
求解算法的时间复杂度的具体步骤是:
-
找出算法中的基本语句;执行次数最多的那条语句就是基本语句,通常是最内层循环的循环体。
-
计算基本语句的执行次数的数量级;只需计算基本语句执行次数的数量级。这就意味着只要保证基本语句执行次数的函数中的最高次幂正确即可,可以忽略所有低次幂和最高次幂的系数。下面我来举一个简单例子:
public static void main(String[] args) { int n = 10, a = 0; for (int i = 1; i <= n; i++) {//时间复杂度为o(n) a++; } for (int i = 1; i <= n; i++) {//时间复杂度为o(n^2) for (int j = 1; j <= n; j++) { a++; } } }
第一个for循环的时间复杂度为o(n),第二个for循环时间复杂度为o(n2),则整个算法的时间复杂度为o(n2+n)。忽略所有低次幂和最高次幂的系数。所以整个算法的时间复杂度为o(n^2)。
补充:为什么可以忽略所有低次幂和最高次幂的系数。举例:(3*n2+4*n+5)
-
当 n 无限大时,3*n^2+4*n 与 3*n^2+4*n+5 的值非常接近,是否加 5 对值影响不大,因此可以简化为 3*n^2+4*n
-
当 n 无限大时,3*n^2 的值远大于 4*n 的值,因此是否加 4*n对值影响不大,因此可以简化为 3*n^2 ;
-
当 n 无限大时,n^2 的值已经超级大,是否乘 3 对最终结果影响不大,因此可以简化为 n^2。
-
再补充:o(1)表示基本语句的执行次数是一个常数,一般来说,只要算法中不存在循环语句,时间复杂度就为o(1)。
空间复杂度
空间复杂度与时间复杂度的的计算方法是一样的。
举例1:计算阶乘 。因为递归调用了 N 次,开辟了 N 个栈帧,每个栈帧使用了常数个空间,故结果为:O(N)
public static long factorial(int n) {
return n < 2 ? n : factorial(n - 1) * n;
}
举例2:计算斐波那契 。因为动态开辟了 N 个空间,故结果为:O(N)
public static int[] fibonacci(int n) {
int[] fibArray = new int[n + 1];//因为动态开辟了 N 个空间,故结果为:O(N)
fibArray[0] = 0;
fibArray[1] = 1;
for (int i = 2; i <= n; i++) {
fibArray[i] = fibArray[i - 1] + fibArray[i - 2];
}
return fibArray;
}
通常来说,只要算法不涉及到动态分配的空间,以及递归、栈所需的空间,空间复杂度通常为0(1);