Sgg:时间复杂度和空间复杂度
面试的时候被问到有关时间复杂度和空间复杂度的问题,有点懵,今天特地整理一下。
其实这两个都是用来形容程序算法的性能好坏。
1 时间复杂度
简单来说,时间复杂度就是程序执行的次数。标志着一个算法的好坏。一般我们用T(n)表示。下面是时间复杂度的一些定义原则。
如果运行时间是常数量级,用常数1表示;
只保留时间函数中的最高阶项;
如果最高阶项存在,则省去最高阶项前面的系数。
下面我尽可能的列举出所有的时间复杂度可能的情况:
1.1 T(n) = 1
用常数1取代运行时间中的所有加法常数 ;
void eat3(int n){
System.out.println("等待一天");
System.out.println("吃一个鸡腿");
}
1.2 T(n)= O(n)
void eat1(int n){
for(int i=0; i<n; i++){;
System.out.println("等待一天");
System.out.println("等待一天");
System.out.println("吃一寸面包");
}
}
vo
最高阶项为3n,省去系数3,转化的时间复杂度为:
T(n) = O(n)
1.3 T(n) = O(logn)
void eat2(int n){
for(int i=1; i<n; i*=2){
System.out.println("等待一天");
System.out.println("等待一天");
System.out.println("等待一天");
System.out.println("等待一天");
System.out.println("吃一半面包");
}
}
最高阶项为5logn,省去系数5,转化的时间复杂度为:
T(n) = O(logn)
举个例子,比如二分法查找元素。我们每次找都要取一半,指导找到那一个元素。8个元素就需要找二分3次。logn就表示他的时间复杂度。
// 二分查找
//
//时间复杂度: log2(N) == lg(N)(最差情况)
int BinarySearch(int* array, int size, int data)
{
int left = 0;
int right = size - 1;
int mid = left + ((right - left) >> 1);
while (left <= right) //表示左闭右闭区间,可以取到边界数值; 如果left<right,表示左闭右开区间
{
if (data == array[mid])
{
return mid;
}
else if (data < array[mid])
{
right = mid - 1;//右边界改变很重要
}
else
left = mid + 1;
}
return -1;
}
1.4 T(n)= O(n^2)
这种的可以拓展到n的多次方,主要取决于循环层数
void eat4(int n){
for(int i=0; i<n; i++){
for(int j=0; j<i; j++){
System.out.println("等待一天");
}
System.out.println("吃一寸面包");
}
}
T(n) =1+2+3+…+n-1+n = 0.5n^2 + 0.5n
最高阶项为0.5n^2,省去系数0.5,转化的时间复杂度为:
T(n) = O(n^2)
1.5 T(n) = O(nlogn)
我们来看这样一段程序:
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j+=i)
{
..... //复杂度为O(1);
}
}
当i=1,执行n次
i=2,执行n/2次;
i=3,执行n/3次;
…
i=n,执行n/n次。
又因为每次执行的时间复杂度都是O(1)。所以整个程序的运行次数就是:
n(1+1/2+1/3+···+1/n) 。
根据泰勒公式展开:
1+1/2+1/3+···+1/n = ln(n+1) + r
所以总的执行次数是 n(ln(n+1)+ r)
因此这段程序的时间复杂度是 O(nlog(n))
1.6 T(n) = O(m×n)
好理解 嵌套循环 ,两层嵌套的循环次数还没有关系 相互独立
1.7 T(n) = O(2^n)
1.8 T(n) = O(n!) 和 T(n) = O(n^n)
例如n张牌的洗牌:
算法一:
for i:=1 to n
do swap(a[i], a[random(i,n)])
时间复杂度是O(n!)算法二:
for i:=1 to n
do swap(a[i], a[random(1,n)])
时间复杂度是O(n^n)
2 空间复杂度
空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度。
①忽略常数,用O(1)表示
②递归算法的空间复杂度=递归深度N*每次递归所要的辅助空间
③对于单线程来说,递归有运行时堆栈,求的是递归最深的那一次压栈所耗费的空间的个数,因为递归最深的那一次所耗费的空间足以容纳它所有递归过程。
1 int a;
2 int b;
3 int c;
4 printf("%d %d %d \n",a,b,c);
创建三个空间 3为常数 与时间复杂度定义方法一样 直接是写为O(1)。
int fun(int n,)
{
int k=10;
if(n==k)
return n;
else
return fun(++n);
}
递归n次每次都要创建一个k,所以是O(n*1) = O(n)