算法:二分算法

引入:程序或算法的时间复杂度

1、一个程序或算法的时间效率,也称“时间复杂度”,有时简称“复杂度”。

2、复杂度常用大的字母O和小写字母n来表示,比如O(n) , O(n2)等。n代表问题规模。

3、时间复杂度是用算法运行过程中,某种时间固定的操作需要被执行的次数和n的关系来度量的。在无序数列中查找某个数,复杂度是O(n)。

4、计算复杂度的时候,只统计执行次数最多的(n足够大时)那种固定操作的次数。比如某个算法需要执行加法n2次,除法n次,那么就记其复杂度是O(n2)的。

5、复杂度有“平均复杂度”和“最坏复杂度”两种(平均复杂度:查一半   最坏复杂度:全部查一遍)两者可能一致也可能不一致。

6、如果复杂度是多个n的函数之和,则只关心随n的增长增长的最快的那个函数

     O(n3+n2)==>O(n3)      O(2n+n3)==>O(2n)     O(n!+3n)==>O(n!)

2n是2的n次方,3n是3的n次方

7、常见复杂度:O(1)     对数复杂度:O(log(n))    线性复杂度:O(n)    多项式复杂度:O(nk)

      指数复杂度:O(an)  阶乘复杂度:O(n!)

8、举例:

    在无序数列中查找某个数(顺序查找)   O(n)

    平面上有n个点,要求出任意两点之间的距离   O(n2)

    插入排序、选择排序、冒泡排序      O(n2)

    快速排序    O(n*log(n))

    二分查找    O(log(n))

回顾插入排序算法:

void InsertionSort(int a[],int size)
{
  for(int i=1;i<size;i++)
  {
   for(int j=0;j<i;j++)
     {
       if(a[j]>a[i])//判断
         {
          int t=a[i];
          for(int k=i;k>j;--k)
              a[k]=a[k-1]//赋值
          a[j]=t;
          break;
         }
     }
  }
}//判断与赋值的操作加起来是复杂度O(n2)
//固定操作:要么作比较要么做赋值

一、二分查找(每通过一次比较,就将查找的范围缩小一半)

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

int BinarySeach(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;
}//复杂度O(log(n));

题目:写一个函数LowerBound,在包含size个元素的、从小到大排序的int数组a里查找比给定整数p小的,下标最大的元素。找到则返回其下标,找不到返回-1。

int LowerBound(int a[],int size,int p)
{
  int l=0;
  int r=size-1;
  int last=-1;
  while(l<=r)
  {
    int mid=l+(r-l)/2;
    if(a[mid]>=p)  r=mid-1;
    else
    {
      last=mid;
      l=mid+1;
    }
  }
return last;
}//复杂度O(log(n))

注意:int mid=(l+R)/2;    防止(l+r)过大溢出:int mid=l+(r-l)/2;

二、二分法求方程的根

题目:求下面方程的一个根:f(x)=x3-5x2+10x-80=0,若求出的根是a,则要求|f(a)|<=10的-6次方。

解法:对f(x)求导,得f'(x)=3x2-10x+10。由一元二次方程求根公式知方程f'(x)无解,因此f'(x)恒大于0,f'(x)单调递增。易知f(0)<0且f(100)>0,所以区间[0,100]内有且只有一个根。由于f(x)在[0,100]内是单调的,所以可以用二分的办法在区间[0,100]中寻找根。

double EP=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 try=1;//记录二分尝试次数
  y=f(root);
  while(fabs(y)>EP)
  {
   if(y>0) x2=root;
   else    x1=root;
   root=x1+(x2-x1)/2;
   y=f(root);
   try++;
  }
printf("%.8f\n",root);
printf("%d",try);
return 0;
}

三、找一对数

题目:输入n(n<=100000)个整数,找出其中的两个数,它们之和等于整数m(假定肯定有解)。题中所有整数都能用int表示。(穷举的复杂度为O(n2)==>100亿超时!)

解法:

1、将数组排序,复杂度是O(n*log(n)) 

2、对数组中的每个元素a[i],在数组中二分查找m-a[i],看能否找到。复杂度long(n),最坏要查找n-2次,所以查找这部分的复杂度也是O(n*log(n))

解法:

1、将数组排序,复杂度是O(n*log(n))

2、查找的时候,设置两个变量i和j,i初值是0,j初值是n-1。看a[i]+a[j],如果大于m,就让j-1,如果小于m,就让i加1,直至m=a[i]+a[j]。

四、农夫和奶牛

题目:农夫john建造了一座很长的畜栏,它包括N(2<=N<=100000)个隔间,这些小隔间的位置为x0,x1,x2....,xN-1(0<=xi<=1000000000均为整数,各不相同)

john的C(2<=C<=N)头牛每头分到一个隔间。牛都希望互相离得远点免得互相打扰。怎样才能使任意两头牛之间的最小距离尽可能的大,这个最大的最小距离是多少?

解法:

1、先得到排序后的隔间坐标x0,x1,x2...xN-1

2、在[L,R]内用二分法尝试“最大最近距离”D=(L+R)/2,(L,R初值为[1,1000000000/c]

若D可行,则记住该D,然后在新[L,R]中继续尝试(L=D+1),若D不可行,则在新[L,R]中继续尝试(R=D-1)

复杂度:log(1000000000/C)*N

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值