程序设计实验之二分算法C++实现

本文探讨了四数求和问题的高效算法,通过预处理和二分查找将时间复杂度降至O(nlogn)。同时,详细解析了如何利用排序和二分查找快速确定中位数,避免了暴力解法的高时间成本。

B-四个数列
在这里插入图片描述
Sample Input

6

-45 22 42 -16

-41 -27 56 30

-36 53 -37 77

-36 30 -75 -46

26 -38 -10 62

-32 -54 -6 45

Sample Output
5

解:事实证明这道题暴力肯定会超时。根据老师在课堂上讲,可以先把A,B两个数组的数自由组合加起来,C,D两个数组的数自由组合加起来,然后利用sort函数把CD排序,对一个有序数组,已知一个元素值,通过二分法查找与之对应的相反数。那么就可以把时间复杂度降为O(nlogn)

#include<algorithm>
using namespace std;
int A[4001],B[4001],C[4001],D[4001];
int n,tag,sum;
int AB[16000001],CD[16000001];
void half(){//折半查找 
 int mid,tag1,tag2;
 for(int i=0;i<tag;i++){
  tag1=0;tag2=tag;
  while(tag2>tag1){
   mid=(tag1+tag2)>> 1;
   if(AB[i] + CD[mid] >= 0)//说明CD[mid]比较大 
    tag2=mid;
   else tag1=mid+1;//CD[mid]比较小   
  }
  while(AB[i]+CD[tag1]==0 && tag1<tag){
   sum++;
   tag1++;
  }
 }
 cout<<sum<<endl;
}
int main(){
 tag=0,sum=0;
 cin>>n;
 for(int i=0;i<n;i++)
  cin>>A[i]>>B[i]>>C[i]>>D[i]; 
 for(int i=0;i<n;i++){
  for(int j=0;j<n;j++){
   AB[tag]=A[i]+B[j];
   CD[tag]=C[i]+D[j];
   tag++;
  }
 }
 sort(CD,CD+tag,less<int>());
 half();
 return 0;
}

在这里插入图片描述
Sample Input

4
1 3 2 4
3
1 10 2

Sample Output

1
8

我再提供一些测试数据吧
Input

5
2 3 4 15 99

6
1 5 13 24 32 45

7
1 2 3 4 5 6 7

Output

12
19
2

解:
同样的,如果这道题采用暴力解法,就是枚举i,j。将ans的结果直接算出来,然后直接得到它的中位数。时间复杂度O(n^2).接下来我们考虑降低时间复杂度的方法:
首先用sort函数将cat数组元素升序排序,也即是去绝对值。说到绝对值,补充概念:abs,fabs(代码说明)

#include<iostream>
#include<math.h>
using namespace std;
int main(){
    int a=5,b=-6,xa,xb;
    xa=abs(a);
    xb=abs(b);
    cout<<xa<<"   "<<xb<<endl;
    return 0;
}

输出结果:
5 6
对于fabs,其适用于浮点数取绝对值,比如fabs(-3.67)=3.67

跳过这段小插曲,我们继续讨论本题。排序后,可以保证cat[j]始终是比cat[i]要大,因为n>=j>i.接着我们就要用二分法去找新数组中位数,怎么找?
首先我们来看看传统的二分法搜索:

int binarySearch(int* array, int target) {
    int left = 0; 
    int right = nums.length - 1; 

    while(left <= right) { 
        int mid = (right + left) / 2;
        if(array[mid] == target)
            return mid; 
        else if (array[mid] < target)
            left = mid + 1; 
        else if (array[mid] > target)
            right = mid - 1; 
        }
    return -1;
}

在一个数组里搜索一个数,如果找到了,就返回其索引,如果找不到,就返回-1.那么上诉的条件是已知一个数组,而且知道我要查找的这个数的值,求其索引。
反观本题,是有一个原始数组,另一个数组可求,知道是中位数,就是我们所说的索引,去找那个数的值,那么我们不妨把right和left由开始的索引(位置)换成值,去找中位数。代码如下(结尾有彩蛋):

#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
int n,mid,maxele,midlocate,tag,tag1,ans,maxlocate;
int cat[100001];
//int ans[10000000001];//cat[j]-cat[i],知道了这个数的位置,去找这个数 
int binarySearch(){
 //int left=0,right=n*(n-1)/2 - 1;
    tag1=maxele;ans=0;
 while(ans < tag1){
     mid=(ans+tag1)/2;tag=0;
  for(int i=0;i<n;i++)
   tag+=n-(lower_bound(cat,cat+n,cat[i]+mid)-cat);
  if(tag > (maxlocate-midlocate))
            ans=mid+1;
        else if (tag <= (maxlocate-midlocate))
            tag1 = mid; 
 }
 ans--;
 return ans;
}
int main(){
 while(scanf("%d",&n)!= EOF){
  for(int i=0;i<n;i++)
   scanf("%d",&cat[i]);
   //cin>>cat[i];
  sort(cat,cat+n,less<int>());
  maxele=cat[n-1]-cat[0];//先找到最大值,它肯定在最后一个位置
  //n*(n-1)/2-1处 
  maxlocate=n*(n-1)/2-1;
  midlocate=(n*(n-1)/2 +1)/2-1;
  
  cout<<binarySearch()<<endl;
 }
 return 0; 
}

这道题的提交过程可谓是一波三折:
在这里插入图片描述它居然不支持less<int>,(╬◣д◢)
解决办法:换为G++
在这里插入图片描述
emmm,我把头文件改为#include<stdio.h>就可以了

但是,它又超时了,原来是cin的问题,用scanf就没事了,为什么呢,难道cin的时候还要去判断一下我输入的是个什么类型,scanf在输入时我就直接告诉它了.(我的粗鄙理解)
放1张可爱猫咪老师图片,美化一下这篇单调的博客:
cute1

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值