由于数组中有可能有重复的元素,所以常规的二分查找并没有详细的举出所有情况...尼玛,昨天才知道自己好水,知道用二分查找能解决的一道题,都搞不定!
这一帖总结下自己遇到过相关的二分查找的题目,引以自鉴。
1、数组中有重复的元素,查找某值第一次出现的位置!
代码:
<span style="font-size:14px;">#include<iostream>
#include<cstring>
using namespace std;
int erfen_find(int *a,int des,int n)
{
int low,high,mid;
low=0;
high=n-1;
while(low<=high) //条件一定要是low<=high,不能使low<high !! 循环结束的条件只有一个!那就是low和high错位!即low>high
{
mid=low+((high-low)>>2);//(low+high)/2
if(a[mid]>=des)high=mid-1; //这里大于等于的判定,移动high游标,
else low=mid+1; //那么low就是结束的标志,结束后指向待查关键字在数组中第一次出现的位置!
}
return low+1;
}
int main()
{
int a[]={1,2,2,3,4,4,6,6,7,9,11};
int n=sizeof(a)/sizeof(int);
int m=erfen_find(a,6,n);
cout<<m;
}</span>
2、数组中有重复的元素,查找某值最后一次出现的位置!
同情况1的代码差别不大,就在于(>=)判定改为(>)判定,返回值选取从low改为high.
<span style="font-size:14px;">#include<iostream>
#include<cstring>
using namespace std;
int erfen_find(int *a,int des,int n)
{
int low,high,mid;
low=0;
high=n-1;
while(low<=high) //条件一定要是low<=high,不能使low<high !! 循环结束的条件只有一个!那就是low和high错位!即low>high
{
mid=low+((high-low)>>2);//(low+high)/2
if(a[mid]>des)high=mid-1; //
else low=mid+1; // 小于等于的判定,移动low游标,那么结束后high游标的位置就是待查关键字在数组中最后一次出现的位置!!!
}
return high+1;
}
int main()
{
int a[]={1,2,2,3,4,4,6,6,7,9,11};
int n=sizeof(a)/sizeof(int);
int m=erfen_find(a,6,n);
cout<<m;
}</span>
-
题目描述:
-
给定两个整型数组A和B。我们将A和B中的元素两两相加可以得到数组C。
譬如A为[1,2],B为[3,4].那么由A和B中的元素两两相加得到的数组C为[4,5,5,6]。
现在给你数组A和B,求由A和B两两相加得到的数组C中,第K小的数字。
-
输入:
-
输入可能包含多个测试案例。
对于每个测试案例,输入的第一行为三个整数m,n, k(1<=m,n<=100000, 1<= k <= n *m):n,m代表将要输入数组A和B的长度。
紧接着两行, 分别有m和n个数, 代表数组A和B中的元素。数组元素范围为[0,1e9]。
-
输出:
-
对应每个测试案例,
输出由A和B中元素两两相加得到的数组c中第K小的数字。
-
样例输入:
-
2 2 3 1 2 3 4 3 3 4 1 2 7 3 4 5
-
样例输出:
-
5 6
-
来源:
- Google面试题
#include<iostream>
#include<algorithm>
using namespace std;
typedef long elem;
elem a[1000001];
elem b[1000001];
elem Match_mid(elem m,elem n,elem mid)
{
elem des=mid;
elem weizhi=0;
elem j=n-1;
for(elem i=0;i<m && j>=0;i++)
{
if(a[i]+b[j]<=des)
{
weizhi+=(j+1);
}
else //if(a[i]+b[j]>=des)
{
while(j>=0 && a[i]+b[j]>des)
j--;//一直自减到a[i]+b[j]<=des ,那么a[i]+b[j+1]>des;
if(j>=0)
weizhi+=(j+1);//小于等于des的数至少有weizhi个!!!
}
}
//mid在数组和中排名第weizhi小 ,同值情况,取最高排名!
return weizhi;
}
elem Find_min_k(elem m,elem n,elem k)
{
elem low=a[0]+b[0];
elem high=a[m-1]+b[n-1];
while(low<=high)
{
elem mid=(low+high)/2;
elem weizhi=Match_mid(m,n,mid);//测mid这个数字在数组中第几小。
if(weizhi>=k)high=mid-1;
else //if(weizhi<k)
low=mid+1;
}
return low;
}
int main()
{
elem m,n,k;
while(cin>>m>>n>>k)
{
for(elem i=0;i<m;i++)
cin>>a[i];
for(elem i=0;i<n;i++)
cin>>b[i];
sort(a,a+m);
sort(b,b+n);//a[m],b[n]都数组输入并排序完毕
elem result=Find_min_k(m,n,k);
cout<<result<<endl;
}
return 0;