今天是释然发题解的第十天,以后每一天都会和大家分享学习路上的心得,希望和大家一起进步,一起享受coding的乐趣。
本文约1200字,预计阅读4分钟
昨天我们学习了二分,忘记的小伙伴们可以看一下哦:
今天我们来聊一聊的二分的相关问题,明天和大家分享分治的相关知识:
题目:整数查找
题目来源:改编
题目描述:输入n(n<=1e6)个数从中间寻找两个数,使得这两个数的和为m
输入:第一行一个数n,第二行n个数
对于20%的数据:n<=100
对于40%的数据:n<=10000
对于100%的数据: n<=1e6
解题思路一:二重循环(模拟)
暴力求解:我们就一个一个找,相加求和不就行了?
碰到按照测试点得分问题我们可以混分
for(int i=1;i<=n-1;i++)
{
for(int j=i+1;j<=n;j++)
{
if(a[i]+a[j]=n) break;
}
}
对于这个方法,想过50%的数据点还是可能卡过去的,也就是说一半的分可以模棱两可混过去,但是在一般的比赛上,一看到这个是O(n^2)的复杂度基本上是过不去的,最后一题连O(n)都可能会超时
解题思路二:二分查找
我们知道想用二分查找,必须先排序:
//C++中自带sort函数,时间复杂度为O(nlogn)
#include<algorithm>
sort(a,a+n);
升序降序无所谓
这个思路就是:第i个数,我们在数组中查找(n-i)看看能不能找到,排序时间复杂度为nlogn,查找最多需要n-2次,复杂度为logn,因此时间复杂度为nlogn
int lastnum,pos,n;
int a[n];
int lowerbound(int *a,int l,int r,int num)
{
int mid;
int lastpos=0;
while(l<r)
{
mid=(l+r)/2;
if(a[mid]==num)
{
return mid;
}
else
{
if(a[mid]>num)
{
r=mid;
}
else
{
l=mid+1;
}
} }
return lastpos;
}
int mian()
{
for(int i=1;i<=n-i;i++)
{ if(lastnum==i) continue;
lastnum=i;//减少不必要的查找
pos=lowerbound(a,i,n,n-a[i]);
if(pos)
{
cout<<a[i]<<a[pos]<<endl;
return 0;
}
}
}
解题思路三:用数组进行二分查找:
我们还是先排序(升序),然后呢我们用两个指针一个左指针一个右指针,如果a[i]+a[j]>n,我们就j–,如果a[i]+a[j]<n,我们就让i++,直到i=j为止
这个算法时间复杂度还是nlogn
while(a[i]+a[j]!=n)
{
if(a[i]+a[j]>n)
{
j--;
}
else
{
i++;
}
}
cout<<a[i]<<a[j]<<endl;
好了,今天的有关二分查找的题目就到这里
释然每天发布一点自己学习的知识,希望2年后我们也能在ACM的赛场上见面,一起去追寻自己的程序猿之路吧!
后期也会和大家一起分享学习心得和学习经验呢,明天我们不见不散哦!
下期预告:
分治和贪心
如果大家有什么建议或者要求请后台留言,释然也想和大家一起进步呀!
联系方式:shirandexiaowo@foxmail.com