二分查找概念
1. 什么是二分查找(Binary Search)
核心思想一句话:👉 每次把搜索范围缩小一半
二分查找是一种在有序数组中查找元素的高效算法。
✅ 前提条件
- 数据必须是有序的(升序或降序)
- 能够通过“大小关系”判断方向
🧠 基本思路
假设在升序数组中找 target:
- 取中间位置
mid -
比较:
-
a[mid] == target→ 找到了 ✅ a[mid] < target→ 去右边找a[mid] > target→ 去左边找- 重复直到找到或区间为空
📌 时间复杂度
- 时间复杂度:O(log n)
- 比线性查找 O(n) 快很多
2. C语言实现
#include <stdio.h>
int binary_search(int a[], int n, int target) {
int left = 0, right = n - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (a[mid] == target) {
return mid; // 返回下标
} else if (a[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1; // 没找到
}
int main() {
int a[] = {1, 3, 5, 7, 9, 11};
int n = sizeof(a) / sizeof(a[0]);
int target = 7;
int pos = binary_search(a, n, target);
if (pos != -1)
printf("找到,下标 = %d\n", pos);
else
printf("未找到\n");
return 0;
}
3. C++实现
#include <iostream>
using namespace std;
int binarySearch(int a[], int n, int target) {
int left = 0, right = n - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (a[mid] == target) return mid;
else if (a[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
int main() {
int a[] = {1, 3, 5, 7, 9, 11};
int n = sizeof(a) / sizeof(a[0]);
int pos = binarySearch(a, n, 7);
if (pos != -1) cout << "找到,下标 = " << pos;
else cout << "未找到";
return 0;
}
4. 进阶:二分查找的两种常见变形
1️⃣ 查找左边界(lower_bound)
👉 找 第一个 ≥ target 的位置
int left_bound(int a[], int n, int target) {
int left = 0, right = n - 1, ans = n;
while (left <= right) {
int mid = (left + right) / 2;
if (a[mid] >= target) {
ans = mid;
right = mid - 1;
} else {
left = mid + 1;
}
}
return ans;
}
2️⃣ 查找右边界(upper_bound)
👉 找 最后一个 ≤ target 的位置
int right_bound(int a[], int n, int target) {
int left = 0, right = n - 1, ans = -1;
while (left <= right) {
int mid = (left + right) / 2;
if (a[mid] <= target) {
ans = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return ans;
}
5. 经典应用实例(重点🔥)
📌 例题:查找某个数是否存在
题目
给定一个升序数组,查询某个数是否存在。
输入
输出
👉 直接用基础二分即可(上面代码)
🎯 例子:最小满足条件的值
题目:
给你一个数组,每个数代表工作量,要求在 k 天内完成,问每天最少做多少?
👉 本质:
- 答案范围是
[max(a), sum(a)] - 判断函数:是否能在 k 天完成
💡 C++代码
#include <iostream>
using namespace std;
bool check(int a[], int n, int k, int limit) {
int days = 1, sum = 0;
for (int i = 0; i < n; i++) {
if (sum + a[i] > limit) {
days++;
sum = a[i];
} else {
sum += a[i];
}
}
return days <= k;
}
int main() {
int a[] = {7, 2, 5, 10, 8};
int n = 5, k = 2;
int left = 10, right = 32, ans = 0;
while (left <= right) {
int mid = (left + right) / 2;
if (check(a, n, k, mid)) {
ans = mid;
right = mid - 1;
} else {
left = mid + 1;
}
}
cout << "最小值 = " << ans;
}
6. 总结
- 二分查找 = 每次砍一半
- 前提:有序
-
核心变量:
-
left,right,mid -
三种类型:
-
普通查找
- 左边界 / 右边界
- 🔥 答案二分(最重要)