用 bisect_left 找到查询值右侧候选,再比较相邻两数的距离。
OJ: noi_openjudge
题目 ID: ch0111-01
难度:普及-
标签:二分排序python
日期: 2026-07-30 23:01
题意
在非降序列中回答多次查询:输出与查询值距离最小的元素;距离相同则选较小值。
思路
bisect_left(numbers, target) 找到第一个不小于查询值的位置。最接近的元素只可能是这个位置或其左邻居;处理越界后比较两边距离。相等时选择左边,正好满足取较小值的规则。
代码
Python代码
python
from bisect import bisect_left
input()
numbers = list(map(int, input().split()))
query_count = int(input())
for _ in range(query_count):
target = int(input())
right = bisect_left(numbers, target)
if right == 0:
print(numbers[0])
elif right == len(numbers):
print(numbers[-1])
else:
left = right - 1
if numbers[right] - target < target - numbers[left]:
print(numbers[right])
else:
print(numbers[left])C++代码
cpp
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
int a[maxn];
int n;
int m;
bool check(int m,int val){
return a[m] >= val;
}
int bs_find(int l,int r,int val)
{
while(l < r) {
int mid = (l+r) >> 1;
if( check(mid,val) == true)
r = mid;
else
l = mid+1;
}
return l;
}
int main(){
cin >> n;
for(int i =1;i<=n;i++)
cin >> a[i];
// sort(a+1,a+1+n);
cin >> m;
for(int i =1;i<=m;i++){
int t;
cin >> t;
int pos = bs_find(1,n+1,t);
if( pos == n+1)
cout << a[n] << endl;
else if( pos == 1){
cout << a[1] << endl;;
}
else if(a[pos] - t >= t-a[pos-1]){
cout << a[pos-1] << endl;
}
else
cout << a[pos] << endl;
}
return 0;
}复杂度
每次查询时间复杂度为
总结
有序序列中的“最接近”问题,只需检查二分定位点附近的两个候选。