算法1-6二分查找与二分答案 —— P2249 查找(来自洛谷 题单)
Posted 青少年信息学交流
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法1-6二分查找与二分答案 —— P2249 查找(来自洛谷 题单)相关的知识,希望对你有一定的参考价值。
P2249 查 找
1. 问题描述
【题目描述】
输入 n(n<=10^6)个不超过 10^9 的单调不减的(就是后面的数字不小于前面的数字)非负整数 a1,a2,a3,......,an,然后进行 m(m<=10^5) 次询问。对于每次询问,给出一个整数 q(q<=10^9),要求输出这个数字在序列中第一次出现的编号,如果没有找到的话输出 -1 。
【输入】
第一行 2 个整数 n 和 m ,表示数字个数和询问次数。
第二行 n 个整数,表示这些待查询的数字。
第三行 m 个整数,表示询问这些数字的编号,从 1 开始编号。
【输出】
m 个整数表示答案。
【输入样例1】
11 3
1 3 3 3 5 7 9 11 13 15 15
1 3 6
【输出样例1】
1 2 -1
2. 问题分析
3. 算法描述
每次用目标值和数组中间位置的元素进行比较:
当目标值等于中间元素,right==mid,就在左半区继续查找(找的是第一次出现的位置,这时mid和mid左边位置的元素都有可能是目标值第一次出现的位置);
当目标值大于中间元素,说明目标值只有可能在后半区出现,left==mid+1;
当目标值小于中间元素,目标值只能在前半区出现,right==mid-1;
我用的递归(或循环)条件是:left<right-1,这样在结束递归或循环时,只能是left<right 且 left+1==right,我们若a[left]==key,就返回left,否则,若a[right]==key,就返回right,不然就返回-1。
当然,还可用c++STL的lower_bound()函数,具体参考下面代码:
4. 代码实现
二分查找(循环):
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <algorithm>
using namespace std;
int a[1000005];
int findnum(int left,int right,int k)
{
while(left<right-1)
{
int mid=left+(right-left)/2;
if(a[mid]==k) right=mid;
else if(k<a[mid]) right=mid-1;
else if(k>a[mid]) left=mid+1;
}
if(a[left]==k) return left;
if(a[right]==k) return right;
return -1;
}
int main()
{
int n,m,k;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) cin>>a[i];
while(m--)
{
scanf("%d",&k);
cout<<findnum(1,n,k)<<" ";
}
return 0;
}
二分查找(递归):
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <algorithm>
using namespace std;
int a[1000005];
int findnum(int left,int right,int k)
{
if(left<right-1)
{
int mid=left+(right-left)/2;
if(k==a[mid]) findnum(left,mid,k);
else if(k>a[mid]) findnum(mid+1,right,k);
else if(k<a[mid]) findnum(left,mid-1,k);
}
else
{
if(a[left]==k) return left;
else if(a[right]==k) return right;
else return -1;
}
}
int main()
{
int n,m,k;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) cin>>a[i];
while(m--)
{
scanf("%d",&k);
cout<<findnum(1,n,k)<<" ";
}
return 0;
}
二分查找(STL):
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <algorithm>
using namespace std;
int a[1000005];
int main()
{
int n,m,k;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) cin>>a[i];
while(m--)
{
scanf("%d",&k);
int p=lower_bound(a+1,a+n+1,k)-a;
if(a[p]==k) cout<<p<<" ";
else cout<<"-1"<<" ";
}
cout<<endl;
return 0;
}
二分查找(vector动态数组):
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
vector<int> v;
int n,m,x,k;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
cin>>x;
v.push_back(x);
}
while(m--)
{
scanf("%d",&k);
int p=lower_bound(v.begin(),v.end(),k)-v.begin();
if(v[p]==k) cout<<p+1<<" ";
else cout<<"-1"<<" ";
}
cout<<endl;
return 0;
}
5. 测试结果
更多精彩内容,请扫描二维码关注!
提高计算思维,编程创造未来!
以上是关于算法1-6二分查找与二分答案 —— P2249 查找(来自洛谷 题单)的主要内容,如果未能解决你的问题,请参考以下文章