二分 - 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;
}
posted @ 2020-03-30 11:18  zhangyue_lala  阅读(382)  评论(0编辑  收藏  举报