【复习】二分查找

👨‍💻 关于作者:会编程的土豆

"不是因为看见希望才坚持,而是坚持了才看见希望。"

你好,我是会编程的土豆,一名热爱后端技术的Java学习者。

📚 正在更新中的专栏:

💕作者简介:后端学习者

原始写法:

cpp 复制代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int n, m;
vector<int>arr;
int main()
{
	cin >> n >> m;
	arr.resize(n + 5);
	for (int i = 1; i <= n; i++)  cin >> arr[i];
	while (m--)
	{
		int left = 1;
		int right = n;
		int tar; cin >> tar;
		while (left <= right)
		{
			int mid = left + (right - left) / 2;
			if (arr[mid] >= tar)
			{
				right = mid - 1;
			}
			else left = mid + 1;
		}
		if (arr[left] == tar)
			cout << left << " ";
		else cout << "-1"<<" ";
	}
	return 0;
}

二分查找进阶:lower_bound 用法详解(附完整代码 + 易错点分析)

在算法题中,"查找一个数是否存在"是非常高频的需求。

lower_bound 是 C++ STL 中最常用、最强大的二分查找工具之一。

你这段代码就是一个典型模板写法,这篇文章带你彻底理解它。


一、问题描述

给定:

  • 一个长度为 n 的数组

  • m 次查询

对于每个查询 x:

复制代码
如果 x 存在,输出它在数组中的位置(从1开始)
如果不存在,输出 -1

二、代码展示

cpp 复制代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int main()
{
    int n, m; 
    cin >> n >> m;

    vector<int> arr;
    for (int i = 0; i < n; i++)
    {
        int x; 
        cin >> x;
        arr.push_back(x);
    }

    while (m--)
    {
        int x; 
        cin >> x;

        auto it = lower_bound(arr.begin(), arr.end(), x);

        if (it == arr.end() || *it != x)
        {
            cout << "-1" << " ";
        }
        else
        {
            cout << it - arr.begin() + 1 << " ";
        }
    }
    return 0;
}

三、核心函数:lower_bound

1. 作用

复制代码
返回第一个 >= x 的位置

2. 举个例子

复制代码
数组:1 3 5 7 9
查询 x 返回位置 指向元素
5 2 5
6 3 7
10 end 越界

四、代码逻辑拆解


1. 查找位置

复制代码
auto it = lower_bound(arr.begin(), arr.end(), x);

2. 判断是否存在

复制代码
if (it == arr.end() || *it != x)

含义:

复制代码
1. 到了末尾 → 不存在
2. 找到的不是 x → 不存在

3. 输出位置

复制代码
it - arr.begin() + 1

说明:

复制代码
迭代器转下标 + 转成1-based

五、一个非常重要的前提

复制代码
数组必须是有序的(升序)

⚠️ 如果不排序会发生什么?

复制代码
结果完全错误(但程序不会报错)

正确做法(建议加上)

复制代码
sort(arr.begin(), arr.end());

六、时间复杂度分析


单次查询

复制代码
O(log n)

总复杂度

复制代码
O(n log n + m log n)

七、常见错误总结


1. 忘记排序

最常见错误:

复制代码
lower_bound 默认要求有序

2. 少写判断

错误写法:

复制代码
cout << it - arr.begin();

可能访问非法位置。


3. 忘记 +1

复制代码
it - arr.begin() + 1

八、进阶理解(非常重要)


lower_bound vs upper_bound

函数 含义
lower_bound 第一个 ≥ x
upper_bound 第一个 > x

举例

复制代码
数组:1 2 2 2 3
x lower_bound upper_bound
2 第一个2 第一个3

九、进阶应用(面试常考)


1. 统计某个数出现次数

复制代码
int count = upper_bound(arr.begin(), arr.end(), x)
          - lower_bound(arr.begin(), arr.end(), x);

2. 查找第一个 ≥ x 的位置


十、一句话总结

复制代码
lower_bound = 找到"第一个不小于 x 的位置"

相关推荐
To_OC7 小时前
LC 128 最长连续序列:别上来就排序,O (n) 解法才是这题的灵魂
javascript·算法·leetcode
刘马想放假19 小时前
Modbus 全栈技术解析:TCP、RTU、ASCII、RTU over TCP
数据结构·网络协议
05Kevin21 小时前
lk每日冒险题--数据结构6.27
算法
To_OC1 天前
从一次栈溢出报错说起,我把递归彻底扒明白了
javascript·算法·程序员
千纸鹤安安2 天前
千问Qwen-AgentWorld来了:一个语言模型搞定七大Agent场景,GPT-5.4都输了
算法
七牛开发者2 天前
MCP 到底是什么?为什么 Agent 都想接上它
算法·aigc·agent
北域码匠2 天前
冒泡排序太慢?鸡尾酒排序双向优化,原生 C# 零第三方库完整代码
数据结构·排序算法·泛型·c# 算法·鸡尾酒排序·原生 c# 开发·冒泡排序优化·嵌入式算法