算法1-6二分查找与二分答案 —— P2249 查找(来自洛谷 题单)

Posted 青少年信息学交流

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法1-6二分查找与二分答案 —— P2249 查找(来自洛谷 题单)相关的知识,希望对你有一定的参考价值。

请点击上面微信号关注精彩内容 提高计算思维,传播编程知识,点亮未来人生!【算法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

说明/提示




This browser does not support music or audio playback. Please play it in Weixin or another browser. 【算法1-6】二分查找与二分答案 —— P2249 查找(来自洛谷 题单)



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 查找(来自洛谷 题单)









更多精彩内容,请扫描二维码关注!

     

提高计算思维,编程创造未来!






以上是关于算法1-6二分查找与二分答案 —— P2249 查找(来自洛谷 题单)的主要内容,如果未能解决你的问题,请参考以下文章

Python数据结构与算法篇-- 二分查找与二分答案

二分与三分

密码破译暴力查找与二分查找

查找算法(二分查找)

算法?日更?第二十四期二分查找和二分答案的区别

算法初体验 —二分查找