文章目录
- 1. 朴素二分查找的基本步骤:
- 2. 总结二分模板
二分查找(Binary Search)是一种在有序数组中查找目标值的高效算法。它的基本思想是将数组分成两半,然后确定目标值可能存在的那一半,重复这个过程直到找到目标值或者确定目标值不存在为止。
1. 朴素二分查找的基本步骤:
- 初始化左右边界:将左边界
left
初始化为数组的起始位置,将右边界right
初始化为数组的结束位置。 - 循环直到左边界小于等于右边界:
- 计算中间位置
mid
:mid = (left + right) / 2。
- 如果目标值等于中间位置的值,则返回中间位置。
- 如果目标值小于中间位置的值,则将右边界移到
mid - 1
。- 如果目标值大于中间位置的值,则将左边界移到
mid + 1
。
- 如果循环结束时仍未找到目标值,则返回不存在的标记(例如
-1
)。
二分查找的时间复杂度为 O(log n),其中 n 为数组的长度。这是因为在每一次迭代中,搜索范围都会减半,直到找到目标值或者搜索范围缩小到零为止。因此,二分查找在大型有序数组中查找目标值时非常高效。
eg1: 最朴素的二分查找
class Solution {
public:
int search(vector<int>& nums, int target) {
int n = nums.size();
// 初始化 left 与 right 指针
int left = 0, right = n-1;
// 由于两个指针相交时,当前元素还未判断,因此需要取等号
while (left <= right) {
// 先找到区间的中间元素
int mid = left + (right-left)/2; // 防止溢出
// 分三种情况讨论
if (nums[mid] < target) {
left = mid+1;
} else if (nums[mid] > target) {
right = mid-1;
} else {
return mid;
}
}
// 如果程序⾛到这⾥,说明没有找到⽬标值,返回 -1
return -1;
}
};
eg2: 在排序数组中查找元素的第⼀个和最后⼀个位置
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int n = nums.size(), begin, end;
if (n == 0) return{-1, -1};
// 1. 查找区间左端点
int left = 0, right = n-1;
while (left < right) {
int mid = left + (right-left)/2;
if (nums[mid] < target) left = mid + 1;
else right = mid;
}
// 判断是否有结果
if (nums[left] != target) return{-1, -1};
else begin = left; // 标记一下左端点
// 2. 查找区间右端点
left = 0, right = n-1;
while (left < right) {
int mid = left + (right-left+1)/2;
if (nums[mid] <= target) left = mid;
else right = mid-1;
}
end = right;
return{begin, end};
}
};
2. 总结二分模板
查找区间左端点的模板:
while (left < right) {
int mid = left + (right - left) / 2;
if (/* 检查目标值是否满足条件 */) {
left = mid + 1;
} else {
right = mid;
}
}
查找区
查找区间的右端点的模板
while (left < right) {
int mid = left + (right - left + 1) / 2;
if (/* 检查目标值是否满足条件 */) {
left = mid;
} else {
right = mid - 1;
}
}
助记:让下面出现-1的时候,上面就+1。
eg3: 搜索插⼊位置
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int n = nums.size();
int left = 0, right = n-1;
// 找到区间左端点
while (left < right) {
int mid = left + (right-left)/2;
if (nums[mid] < target) left = mid+1;
else right = mid;
}
if (nums[left] < target) return right+1;
else return right;
}
};
eg4: x 的平⽅根
class Solution {
public:
int mySqrt(int x) {
if (x < 1) return 0; // 处理边界情况
int left = 0, right = x;
while (left < right) {
long long mid = left + (right-left+1)/2; // 用long long mid*mid防止溢出
if (mid*mid <= x) left = mid;
else right = mid-1;
}
return left;
}
};