二分 - bailian 4134:查找最接近的元素
题目链接
http://bailian.openjudge.cn/practice/4134/
分析一波
题目要在一个比较大的非降序列表中,寻找最接近给定值a的列表中元素,如果使用顺序查找,很可能就超时了,在这里,考虑使用二分查找。
二分查找一定要求待查找序列有序,在二分查找中,判定查找结束的条件是 low > high,因为这里low == high 也是允许的,如果没有找到一个给定元素,那么这个元素一定是夹在 List[high] 和 List[low]之间。
二分作为一种算法思想,其应用范围不仅限于查找,也可进行枚举,比如我们熟悉的用二分法寻找方程的根,需要枚举一个范围内的所有点,使用二分法就可以每次将这个范围减半,从而加快根的寻找。但是使用二分需要待查找数据满足某种"单调性",在二分查找中,需要带查找序列有续,所以能够在待查元素与中间元素比较后,能够将一半的元素排除掉;在求方程根的问题中,需要函数在一段区间内保持单调,所以在中点的函数值大于0的时候能排除一半的区间。
其他二分的应用场景都有类似单调的限制。
解题代码
#include <cstdio>
#include <cstring>
#define MAX 100010
int List[MAX];
int n;
int main(){
scanf("%d", &n);
memset(List, 0, sizeof(List));
for(int i = 0; i < n; i++){
scanf("%d", List + i);
}
int m;
scanf("%d", &m);
while(m--){
int a;
scanf("%d", &a);
int low = 0, high = n - 1, mid = (low + high)/2;
while(low <= high){
mid = (low + high) / 2;
if(List[mid] > a) high = mid - 1;
else if(List[mid] < a) low = mid + 1;
else break;
}
if(low <= high)
printf("%d\n", List[mid]);
else{
if(high < 0)
printf("%d\n", List[0]);
else if(low >= n)
printf("%d\n", List[n - 1]);
else if(List[low] - a >= a - List[high])
printf("%d\n", List[high]);
else if(List[low] - a < a - List[high])
printf("%d\n", List[low]);
}
}
return 0;
}
你若笃定,世界便不浮躁。