Files
mengyanote/mengyanote-backend/mengyanote/.trash/二分查找左侧边界算法总结.md
2025-12-19 15:51:26 +08:00

2.3 KiB
Raw Blame History

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

题目描述

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

输入格式

  1. 第一行:一个整数 n,表示数组元素个数(n <= 10^5)。
  2. 第二行n 个整数,代表数组元素(1 <= 数组元素的值 <= 10^8)。
  3. 第三行:一个整数 q,表示查询的数个数(q <= 10^5)。
  4. 第四行q 个整数,代表要查找的值(1 <= 要查找的数 <= 10^8)。

输出格式

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

算法思路

  1. 初始化
    • 设置左右指针 lr,分别指向数组的开始和结束。
    • 初始化结果 res 为 -1。
  2. 二分查找
    • l小于等于r时,执行以下步骤:
      • 计算中间索引 m
      • 如果 a[m] 等于 x,更新 resm + 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#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 

总结

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