2.3 KiB
2.3 KiB
二分查找左侧边界算法总结
题目描述
在一个有序不递减的数组中(可能包含重复元素),使用二分查找找到某个值 x 第一次出现的位置。如果该值不存在,则返回 -1。
输入格式
- 第一行:一个整数
n,表示数组元素个数(n <= 10^5)。 - 第二行:
n个整数,代表数组元素(1 <= 数组元素的值 <= 10^8)。 - 第三行:一个整数
q,表示查询的数个数(q <= 10^5)。 - 第四行:
q个整数,代表要查找的值(1 <= 要查找的数 <= 10^8)。
输出格式
输出每个查询对应的第一次出现的位置,若不存在则输出 -1。
算法思路
- 初始化:
- 设置左右指针
l和r,分别指向数组的开始和结束。 - 初始化结果
res为 -1。
- 设置左右指针
- 二分查找:
- 当
l小于等于r时,执行以下步骤:- 计算中间索引
m。 - 如果
a[m]等于x,更新res为m + 1,并将r移动到m - 1继续向左查找。 - 如果
a[m]小于x,将l移动到m + 1。 - 如果
a[m]大于x,将r移动到m - 1。
- 计算中间索引
- 当
- 输出结果:
- 返回结果
res。
- 返回结果
时间复杂度
- 每次查找的时间复杂度为 O(log n),因此总时间复杂度为 O(q log n)。
示例代码
c#include <stdio.h>
int findLB(int a[], int n, int x) {
int l = 0, r = n - 1, res = -1;
while (l <= r) {
int m = l + (r - l) / 2;
if (a[m] == x) {
res = m + 1;
r = m - 1;
} else if (a[m] < x) {
l = m + 1;
} else {
r = m - 1;
}
}
return res;
}
int main() {
int n, q;
scanf("%d", &n);
int a[n];
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
scanf("%d", &q);
int qry[q];
for (int i = 0; i < q; i++) {
scanf("%d", &qry[i]);
}
for (int i = 0; i < q; i++) {
int pos = findLB(a, n, qry[i]);
printf("%d ", pos);
}
printf("\n");
return 0;
}
c
示例
输入
6
1 2 2 2 3 3
3
3 2 5
输出
5 2 -1
总结
该算法有效地使用二分查找来找到数组中元素的左侧边界,适合处理较大规模的输入数据。