二分查找&&二分中位数

普通二分查找

 1 int bs(int L,int R,int x)
 2 {//在l到r区间上查找x,找不到就返回-1
 3     int l=L,r=R;
 4     while(l<=r){
 5         int m=l+r>>1;
 6         if(a[m]==x){
 7             return m;
 8         }
 9         else if(a[m]>x){
10             r=m-1;
11         }
12         else{
13             l=m+1;
14         }
15     }
16     return -1;
17 }

普通版很简单就不详细总结了

二分查找中位数

题意:给定长度为n的两个有序序列,求两个序列合并后的中位数

直接归并法,找到第(2n+1)/2数时停止并输出答案,复杂度为O(n)

但题目要求logn,我们就得换个思路了;

题目给的是两个有序序列,所以两个序列的中位数都可以O(1)求得,那么最终答案的中位数和这两个序列的中位数有什么关系呢?假设第一个序列叫a,中位数为ma,第二个是b,中位数为mb,他们的并集是c,最终答案为ans。

如果ma==mb,也就是说,ma的两端和mb的两端分别在ans的两端,ans也就是ma+mb>>1,也就是随便一个了

如果ma<mb,也就是说,a的中位数比b的要小,所以a的左边和b的右边可以不用考虑了,ans一定在ma与mb中间

如果ma>mb,情况同上,把b视作a,a视作b即可

那么每一次都可以删掉c的一半,直到达到终止条件(假装知到),复杂度就是O(logn)了!

 1 #include<iostream>
 2 using namespace std;
 3 int a[100010],b[100010];
 4 int n;
 5 int bs(int la,int ra,int lb,int rb){
 6     int ma=la+ra>>1;
 7     int mb=lb+rb>>1;
 8     if(a[ma]==b[mb]){
 9         return a[ma];
10     }
11     if(a[ma]<b[mb]){
12         bs(la,ra,lb,rb);
13     }
14     else if(a[ma]>b[mb]){
15         bs(la,ra,lb,rb);
16     }
17 }
18 int main()
19 {
20     cin>>n;
21     for(int i=1;i<=n;i++)
22         cin>>a[i];
23     for(int i=1;i<=n;i++)
24         cin>>b[i];
25     cout<<bs(1,n,1,n);
26 }
View Code

至此我们可以写出这样的代码,还缺了点边界情况和终止条件。

那么极端情况是什么呢,ab序列都只有一个的时候,最终答案自然是小的那个,

那么跑一遍样例,看看有没有错,发现了死循环:

当a序列为3 5 ,b序列为4 时,ma=3,mb=4,ma的左边和mb的右边删无可删了,所以这算一种边界情况。

推广,当总序列只有三个元素时,算一种边界情况,那么最终答案肯定是三个数中间那个数,我的做法:出现两序列不等长的时候,让小的那个序列左指针右移一就行,然后就会回到第一种终止条件!

代码:

 1 #include<iostream>
 2 using namespace std;
 3 int a[100010],b[100010];
 4 int n;
 5 int bs(int la,int ra,int lb,int rb){
 6     int ma=la+ra>>1;
 7     int mb=lb+rb>>1;
 8 
 9     if(la==ra){
10         return a[ma]<b[mb]?a[ma]:b[mb];
11     }
12     if(a[ma]==b[mb]){
13         return a[ma];
14     }
15     if(a[ma]<b[mb]){
16         la=ma;
17         rb=mb;
18         if(ra-la!=rb-lb)
19         ra-la > rb-lb ? la++ :lb++;
20         bs(la,ra,lb,rb);
21     }
22     else if(a[ma]>b[mb]){
23         lb=mb;
24         ra=ma;
25         if(ra-la!=rb-lb)
26         ra-la > rb-lb ? la++ :lb++;
27         bs(la,ra,lb,rb);
28     }
29 }
30 int main()
31 {
32     cin>>n;
33     for(int i=1;i<=n;i++)
34         cin>>a[i];
35     for(int i=1;i<=n;i++)
36         cin>>b[i];
37     cout<<bs(1,n,1,n);
38     return 0;
39 }
View Code

 输入的复杂度为O(n),查找的复杂的为O(logn),总复杂度为O(logn)  (手动滑稽)。

    

猜你喜欢

转载自www.cnblogs.com/qq2210446939/p/11571934.html