二分查找
在一个1~n的递增序列中,怎么用二分查找数字x的下标?
在一个没用重复元素的递增序列中,用二分查找的方法最多需要查找log(n)次,也就是在一个区间内l~r不断的选取中间下标(mid),直到mid等于需要查找的数。这种查找方法在最坏的情况下能以很少的执行次数找到数。
而C++的二分查找实现是这样的:
- 对于一个区间有左指针 和右指针 。
- 在所有数字代表的区间,尝试中间下标 (mid)。
- 如果中间下标对应的数字就是答案则输出答案。
- 如果数字太小,则继续处理右区间。
- 如果数字太大,则继续处理左区间。
程序中的重要变量:
- a[100010] 输入的有序递增序列
- n 序列中数字的个数
- x 要查询的数字
- l,r,mid 左指针,右指针,中间下表
- ans 答案,中间下标等于x时下标的数
#include <bits/stdc++.h>
int a[1000010];
using namespace std;
int main() {
int n, x;
cin >> n;
for(int i = 1; i <= n; i++)
cin >> a[i];
cin >> x;
int l = 1, r = n, ans = -1;
// 左指针是第一个元素的下标,右指针是最后一个元素的下标
while (l<=r) { // 只要左指针不大于右指针,就不断地循环。
int mid = (l+r)/2; // 中间下标是左右指针的平均值
if (a[mid] == x) { // 如果中间下标对应的值刚好是要找的那个
ans = mid; // 记录答案并返回
break;
} else if (a[mid]>x) // 如果中间下标对应的值比要找到更大
r = mid-1; // 右指针缩到中间下标的左边一个
else // 如果中间下标对应的值比要找到小
l = mid+1; // 左指针缩到中间下标的右边一个
}
cout << ans; // 输出答案
}
查找第一个出现的位置时,可以这样执行
while (l <= r) {
int mid = (l + r) / 2;
if (a[mid] == x) { // 如果中间的数字等于要找的
ans = mid; // 记录答案位置
r = mid-1; // 局限在左区间
} else if (a[mid] > x) // 如果中间数字大于要找的
r = mid-1; // 局限在左区间
else // 如果中间数字小于要找的
l = mid+1; // 局限在右区间
}
查找最后一个出现的位置时,可以这样执行
while (l <= r) {
int mid = (l + r) / 2;
if (a[mid] == x) {
ans = mid;
l = mid+1;
} else if (a[mid] > x)
r = mid-1;
else
l = mid+1;
}
P1102 A-B 数对
题面
题目背景
出题是一件痛苦的事情!
相同的题目看多了也会有审美疲劳,于是我舍弃了大家所熟悉的 A+B Problem,改用 A-B 了哈哈!
题目描述
给出一串正整数数列以及一个正整数 C,要求计算出所有满足 A−B=C 的数对的个数(不同位置的数字一样的数对算不同的数对)。
输入格式
输入共两行。
第一行,两个正整数 N,C。
第二行,N 个正整数,作为要求处理的那串数。
输出格式
一行,表示该串正整数中包含的满足 A−B=C 的数对的个数。
输入输出样例
输入 #1
4 1 1 1 2 3
输出 #1
3
题解
代码
#include <bits/stdc++.h>
int a[200010], n, c;
long long ans = 0;
using namespace std;
int findx(int k) { // 找到第一次出现的位置
int l = 1, r = n, ans = -1;
while (l <= r) {
int mid = (l + r) / 2;
if (a[mid] == k) { // 如果中间的数字等于要找的
ans = mid; // 记录答案位置
r = mid-1; // 局限在左区间
} else if (a[mid] > k) // 如果中间数字大于要找的
r = mid-1; // 局限在左区间
else // 如果中间数字小于要找的
l = mid+1; // 局限在右区间
}
return ans;
}
int findy(int k) { // 找到最后一次出现的位置
int l = 1, r = n, ans = -1;
while (l <= r) {
int mid = (l + r) / 2;
if (a[mid] == k) {
ans = mid;
l = mid+1;
} else if (a[mid] > k)
r = mid-1;
else
l = mid+1;
}
return ans;
}
int main() {
cin >> n >> c;
for(int i = 1; i <= n; i++)
cin >> a[i];
sort(a + 1, a + n + 1);
for(int i = 1; i <= n; i++) {
int x = findx(a[i] + c);
int y = findy(a[i]+c);
if(x == -1) continue;
ans += y-x+1;
}
cout << ans; // 输出答案
}