问题 G: C 语言习题 折半查找
时间限制: 1.00s | 内存限制: 128MB
题目描述
有 n 个数(n≤1000000),这 n 个数已按从大到小顺序存放在一个数组中,然后有 T 次查询,每次输入一个数,要求用折半查找法找出该数在数组中第一次出现的位置。如果不在数组中输出 0
。
输入
第一行数组元素的个数 nnn。
第二行 nnn 个数组元素的值。
第三行输入查询次数 T(T≤100000)。
往下有 T 行,每行输入一个需要查询的数字。
输出
查找的值在数组中的位置。
输入输出样例
样例输入 #1
复制
10
10 9 8 7 6 5 4 3 2 1
2
9
5
样例输出 #1
复制
2
6
提示
注意:数组空间为 1000000 和 100000。
tips:使用 scanf
和 printf
会更快哦
我们大家都知道升序的二分如何查找第一个大于等于x 的数字所在的下标,可是你知道如果是降序,你又该如何应呢?
其实二分的关键就是在画图,可以分为两个区间,判断这个数是否满足某个性质,哪个区间段满足这个性质。
升序我们找某个数第一次出现的位置,寻找的是第一次大于这个数,降序寻找的就是第一次小于等于这个数
这道题呢,因为它是降序,我们要找某个数字第一次出现的位置,其实就是找第一个小于等于x 的数字的下标,
比如
a[i] 10 9 8 7 7 6 5 4 3 2
i 1 2 3 4 5 6 7 8 9 10
如果mid满足判断条件(a[mid]<=x),并不能说明mid 就是第一个小于等于x的数,mid 右侧的数肯定都满足<=x ,但我们要寻找第一个小于等于x 的数,因此要将r 更新成mid ,即答案在左半边区间,如果不满足条件(即a[mid]>x) ,答案肯定在mid 右侧的区间而且不包含mid ,即l=mid+1;
举个例子吧:比如你要找的数字是7, 你mid 是6,a[6]<=7,因为是降序,答案肯定在左边。
它已经小于7了,右边一定小于7 ,你要找第一次小于等于7的,肯定要往左半边(数大的位置)找。
代码实现:
#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
int a[N];
int main()
{
int n;
cin>>n;
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
int T;
cin>>T;
while(T--)
{
int x;
scanf("%d",&x);
int l=1,r=n;
while(l<r)
{
int mid=l+(r-l)/2;
if(a[mid]<=x) r=mid;
else l=mid+1;
}
if(a[l]!=x) printf("0\n");
else printf("%d\n",l);
}
return 0;
}