在leetcode做了这么多题了,总是会看到时间复杂度和空间复杂度这两个字眼,但是能把题做出来调试好已经万事大吉咯!
今天恰好看到专门讲述这俩概念的文章,希望能加深理解~
前言
所谓算法,其实就是我们用来操作数据、解决程序问题的一组方法。针对同一个问题,我们可以采用不同的算法,然后实现相同的结果。但是针对不同的算法,对于时间和资源的消耗却有不同的差别。而为了分析不同算法的效率,我们常常从 时间 和 空间 两个方面来对比,然后从中挑出最适合我们的解决方案。
本文主要从时间复杂度和空间复杂度的定义说起,然后介绍常见的时间复杂度和空间复杂度,最后则是对常见排序算法进行了总结。
第一个概念:时间复杂度
1 定义:
2 推导时间复杂度的原则
3 分析时间复杂度的方法
总结起来,对于如何分析一段代码的时间复杂度,主要有如下 3 个实用方法:
只关注循环执行次数最多的一行代码;
加法原则:总复杂度等于量度最大的那段代码的复杂度;
乘法原则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积;
4 常见的时间复杂度曲线
5 常见的时间复杂度
O(1)
即无论执行多少行,都不会影响到其他区域,此时代码的复杂度就是 O(1),如下面的代码中,假设执行每行代码时间都相同为t ,则 2,3 行各需 1 个执行时间,即为 $t + t = 2t。此时执行时间复杂度为常数。
void sayHello(String name){
System.out.prinln("Hello, " + String); //需要一个执行时间
System.out.prinln("你好:Mrliang");//需要一个执行时间
}
在这里插入代码片
O(logn)
如下列二分查找代码中,通过 while 循环,能够成倍的缩减搜索范围,假设需要 x 次才能跳出循环,则有 num * 2 * 2 * … = n ,其中 num 是常数,有 n 个 2 相乘,则有num*2x=n ,从而推出 x=log2(n/num),因此时间复杂度用大 O 表示法表示为 O(logn)
//顺便复习一下二分查找
int binarySearch(int[] arr, int target){
int left = 0;
int right = arr.length - 1;
while(left <= right){
int middle = left + (left - right) / 2;
if(arr[middle] == target){
return middle;
}else if(arr[middle] > target){
right = middle - 1;
}else {
left = middle + 1;
}
}
return -1;
}
在这里插入代码片
O(n)
如下面这段代码中,for 循环中的代码被执行了 arr.length 次,因此所需要的时间和数组长度成正比的,因此可以用 O(n)来表示它的时间复杂度。利用上述推到原则和分析的方法,可以知道下面代码中循环次数最多的是 4,5 行,总的执行时间是O(2n) ,抛去系数后,得到最终时间复杂度O(n) .for循环的时间复杂度
int sum(int[] arr){
int total = 0;
for(int i = 0; i < arr.length; i++){
total += arr[i];
}
return total;
}
在这里插入代码片
O(nlogn)
将一个时间复杂度为O(nlogn)的代码重复执行次,那么此时的代码的复杂度就是O(nlogn)
嵌套循环
void hello (int n){
for( int i = 1 ; i < n ; i++){
int m = 1;
while( m < n ){
m *= 2;
}
}
}
在这里插入代码片
O(n2)
将时间复杂度为O(n)的代码重复执行n次,此时的时间复杂度就是O(n2)
双重循环 实现两个数的交换
void selectionSort(int[] arr, int n){
for(int i = 0; i < n; i++){
int min = i;
for(int j = i + 1; j < n; j++){
if(arr[j] < arr[min]){
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
}
}
在这里插入代码片
O(n3)
三种嵌套循环:将时间复杂度为O(n2)的代码嵌套循环一次
void demo(int n){
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
for(int k = 0; k < n; k++){
System.out.print("Hello, World");
}
System.out.print("------");
}
System.out.print("******");
}
}
在这里插入代码片
第二个概念:空间复杂度
定义
空间复杂度是对一个算法在运行过程中临时占用存储空间大小的一个量度(即除开原始序列大小的内存,在算法过程中用到的额外的存储空间),反映的对内存占用的趋势,而不是具体内存,也叫作 渐进空间复杂度 ,表示算法的存储空间与数据规模间的增长关系,用 来代替;
常用空间复杂度:
O(1)
算法执行所需临时空间不随某一变量 n 的大小而变化,则该算法空间复杂度为一个常量,表示为 S(n)=O(n);
int num1 = 1;
int num2 = 2;
int total = num1 + num2;
在这里插入代码片
O(n)
数组占用内存大小为 n,而且后续未分配新的空间,因此该算法空间复杂度为 S(n)=O(n)
int[] arr=new int[n];
在这里插入代码片
O(n2)
二维数组的情况:
int[][] arr=new int[n][n];
在这里插入代码片
附 常见排序算法的时间复杂度和空间复杂度