程序或算法的时间复杂度--算法--笔记

一:概念和分类

概念:
一个程序或算法的时间效率,也称时间复杂度,复杂度
计算复杂度的秩统计执行次数最多的那种固定操作的次数。

分类:平均复杂度和坏复杂度

注意:如果复杂度时多个n的函数之和,则只关心随n的增长增长最快的那个函数
| 名称|复杂度 |
|--|--|
| 常数复杂度 |o(1) |
| 对数复杂度|o(log(n))|
|线性复杂度 |o(n) |
|多项式复杂度|o(n的k次方) |
|指数复杂度|o(a的n次方)|
|阶乘复杂度|o(n!)|
|插入排序,选择排序,冒泡排序|o(n方)|
|快速排序|o(n*log(n))|
|二分查找|o(log(n))|

二:关于复杂度的计算

问题

A心里想一个1-10000之间的数,B来猜,可以问问题,A只能回答
是或者否。
怎么猜才能问的问题次数最少?

非二分

是1吗?是2吗?。。。。是999那? 平均要问500次

二分法

大于500?大于750?大于625? 每次缩小猜测范围到上次的一半,只需要10次

二分查找函数

写一个函数BinarySeach,在包含size个元素的,从小到大排序的int数组a里查找元素p,如果找到则返回元素下标,如果找不到则返回-1.要求复杂度o(log(n))

BinarySearch

int BinarySearch(int a[],int size,int p)
{
 int L=0;//查找区间的左端点
 int  R=size-1;//查找区间的右端点
 while(l<R){//如果查找区间不为空就继续查找
  int mid=L+(R-L)/2;//取查找区间正中元素的下标
  if (p==a[mid])
   return mid;
  else if(p>a[mid])
   L=mid+1;//设置新的查找区间的左端点
  else 
   R=mid-1;//设置新的查找区间的右端点
}
 return -1;
}

写一个函数LowerBound,在包含size个元素的,从小到大排序的int数组a里查找比给的那个整数小的,下表达的元素。

int LowerBound(int a[],int size,int p)//复杂度o(log(n))
{
 int L=0;//查找区间的左端点
 int R=size-1;//查找区间的右端点
 int lastPos=-1;//到目前为止找到的最优解
 while(L<R){//如果查找区间不为空就继续查找
  int mid=L+(R-L)/2;//取查找区间中元素的下表
  if(a[mid]>=p)
   R=mid-1;
  else{
   lastPos=mid;
   L=mid+1;
  }
 }
 return lastPos;
}

注意

注意:int mid=(L+R)/2;//取查找区间正中元素的下标
为了防止(L+R)过大溢出 int mid=L+(R-L)/2;

三:二分法求方程的根

问题:

求下面一个方程的一个根:f(x)=x^3-5x^2+10x-80=0;
求出的根位a,则要求|f(a)|<=10^-6;
解法:对f(x)求导,由一元二次方程求根公式知方程f(x)
的导函数=0无解,因此f(x)的导函数恒大于0.故f(x)单调增
f(x)在[0.100]内有一个根,所所以考虑二分法。

二元法求方程的根

double EPS=1e-6;
double f(double x){return x*x*x-5*x*x+10*x-80;}
int main(){
 double root,x1=0,x2=100,y;
 root=x1+(x2-x1)/2;
 int triedTimes=1;//记录一共尝试多少次
 y=f(root);
 while(fabs(y)>EPs){
  if(y>0) x2=root;
  else x1=root;
  root=x1+(x2-x1)/2;
  y=f(root);
  triedTimes++;
 }
 printf("%0.8f\n",root);
 printf("%d",triedTimes);
 return 0;
}

四:案例:复杂度与使用算法

问题

输入n(n<=100000)个整数,找出其中的两个数,他们之和
等于整数m(假定肯定有解)。题中所有整数都能用int表示

解法一

用两重循环,枚举所有的取数方法,复杂度是0(n2)的。

for(int i=0;i<n-1;++i)
  for(int j=i+1;j<n;++j)
   if(a[i]+a[j]==m)
    break;

100000*100000=100亿,在各种OJ上提交或参加程序
设计竞赛,这样的复杂度肯定会超时!

解法二

1)将数组排序,复杂度o(nlog(n))
2)对数组的每个元素a[i],在数组中二分查找m-a[i],看能否
找到。复杂度log(n),最坏也要查找n-2次,所以查找这部分的复杂度也是o(n
log(n))
这种解法的复杂度是o(n*log(n))

解法三

1)将数组排序,复杂度o(nlog(n))
2)查找的时候,设置两个变量i和j,i的初值为0,j的初值为n-1看a[i]+a[j],如果大于m,就让j减1,如果小于m就让i加1,直至a[i]+a[j]=m;
这种解法的复杂度为o(n
log(n))

问题

农夫john建造了一座很长的畜栏,它包括N(2<=N<=100000)
个隔间这些小隔间的位置为x0,x1.....xN1(0=<xi<1000000000,均为整数,各不相同)
John的C(2<=C<=N)头牛每头分到一个隔间,牛希望互相离得远点,省的互相打扰,怎样才能使任意两头牛之间的最小距离尽可能的大,这个最大的最小距离是多少呢。

解法一

先得到排序后的隔间坐标x0....xN-1;
从1000000000/C到1依次尝试这个"最大的最近距离D",找到的第一个可行的就是答案。

尝试方法:
1)第一头牛放在x0
2)若第k头牛放在xi,则找到xi+1到xN-1中第一个位于[xi+D,1000000000]中的xj
第k+1头牛放在xj.中不到这样的xj,则D=D-1)再试
若所有的牛都能放下,则D即答案

复杂度:10000000000/C*N,即1000000000超时
解法二:

先得到排序后的隔间坐标x0....xN-1
在[L,R]内用二分法尝试"最大最近距离"D=(L+R)/2,(L,R初值为[1,1000000/C])
若D可行,则记住该D,然后再新的[L+R]中继续尝试(L=D+1)
若D不可行,则在新[L,R]中继续尝试(R=D-1)

复杂度 log(1000000000/C)*N

猜你喜欢

转载自www.cnblogs.com/available/p/12529429.html