# 二分查找左侧边界算法总结



## 题目描述



在一个有序不递减的数组中（可能包含重复元素），使用二分查找找到某个值 `x` 第一次出现的位置。如果该值不存在，则返回 -1。



## 输入格式



1. **第一行**：一个整数 `n`，表示数组元素个数（`n <= 10^5`）。
2. **第二行**：`n` 个整数，代表数组元素（`1 <= 数组元素的值 <= 10^8`）。
3. **第三行**：一个整数 `q`，表示查询的数个数（`q <= 10^5`）。
4. **第四行**：`q` 个整数，代表要查找的值（`1 <= 要查找的数 <= 10^8`）。



## 输出格式



输出每个查询对应的第一次出现的位置，若不存在则输出 -1。



## 算法思路



1. **初始化**：
   - 设置左右指针 `l` 和 `r`，分别指向数组的开始和结束。
   - 初始化结果 `res` 为 -1。
2. **二分查找**：
   - 当`l`小于等于`r`时，执行以下步骤：
     - 计算中间索引 `m`。
     - 如果 `a[m]` 等于 `x`，更新 `res` 为 `m + 1`，并将 `r` 移动到 `m - 1` 继续向左查找。
     - 如果 `a[m]` 小于 `x`，将 `l` 移动到 `m + 1`。
     - 如果 `a[m]` 大于 `x`，将 `r` 移动到 `m - 1`。
3. **输出结果**：
   - 返回结果 `res`。



## 时间复杂度



- 每次查找的时间复杂度为 O(log n)，因此总时间复杂度为 O(q log n)。



## 示例代码



```c
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 
```



## 总结



该算法有效地使用二分查找来找到数组中元素的左侧边界，适合处理较大规模的输入数据。