题目描述
一群喵,每只喵都有一个数字,现在肥成想知道它的朋友有几个,肥成会告诉我们它的朋友的数字的范围。
输入格式
第一行两个整数N,T,代表共有N只喵,T次询问。
第二行是N个整数,代表N只喵的数字。
之后T行,每行两个整数l,r,代表是肥成的朋友的数字的范围。
数据范围
对于50%50%的数据有1≤n≤1000,1≤ai≤1000,T=1000。
对于80%80%的数据有1≤n≤10000,1≤ai≤10000,T=1000。
对于100%100%的数据有1≤n≤100000,1≤ai≤100000,T=1000。
输出格式
对于每个询问,请输出肥成的朋友的个数。
样例解释
样例输入
10 3 1 3 4 4 5 8 8 10 10 10 2 6 4 8 6 7
样例输出
4 5 0
题目做法较多,但推荐使用二分,效率很高;
枚举也是可行方案,但在数据规模庞大时效率低下。
#include <iostream>
#include <algorithm>
static unsigned int binary_search1(register unsigned int * range, register unsigned int head, register unsigned int rear, register unsigned int target) {
register unsigned int middle = (head + rear) / 2;
if (range[middle] < target) {
if (middle == rear) {
return 0;//无效
}
if (range[middle + 1] >= target) {
return middle + 1;
}
if ((middle + rear) / 2 == middle) {
return binary_search1(range, middle, rear + 1, target);
}
return binary_search1(range, middle, rear, target);
}
if (range[middle] > target) {
if (middle == 0) {
return 0;//有效
}
if (range[middle - 1] < target) {
return middle;
}
if ((head + middle) / 2 == middle) {
return binary_search1(range, head, middle + 1, target);
}
return binary_search1(range, head, middle, target);
}
else {
while (range[middle] == target) {
if (middle == 0) {
return middle;
}
middle--;
}
return middle + 1;
}
}//寻找大于等于目标的最左边的数
static unsigned int binary_search2(register unsigned int* range, register unsigned int head, register unsigned int rear, register unsigned int target) {
register unsigned int middle = (head + rear) / 2;
if (range[middle] > target) {
if (middle == 0) {
return 0; //无效
}
if (range[middle - 1] <= target) {
return middle - 1;
}
if ((head + middle) / 2 == middle) {
return binary_search2(range, head, middle + 1, target);
}
return binary_search2(range, head, middle, target);
}
if (range[middle] < target) {
if (middle == rear) {
return middle;
}
if (range[middle + 1] > target) {
return middle;
}
if ((middle + rear) / 2 == middle) {
return binary_search2(range, middle, rear + 1, target);
}
return binary_search2(range, middle, rear, target);
}
else {
while (range[middle] == target) {
if (middle == rear) {
return middle;
}
middle++;
}
return middle - 1;
}
}//寻找小于等于目标的最右边的数
int main() {
register unsigned int n, t, * a, l, r;
std::cin >> n >> t;
a = new unsigned int[n];
for (register unsigned int i = 0; i < n; i++) {
std::cin >> a[i];
}
std::sort(a, a + n);
for (register unsigned short i = 0; i < t; i++) {
std::cin >> l >> r;
std::cout << binary_search2(a, 0, n - 1, r) - binary_search1(a, 0, n - 1, l) + 1 << "\n";
}
return 0;
}
两者(穷举 vs 二分)对比结果如下:
提示:需注意使用二分时应注意避免中间值反复取相同的值导致死循环从而堆栈溢出,应该注意判断新计算的中间下标是否与现有的重复