文章目录
- 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;}}// 如果程序⾛到这⾥,说明没有找到⽬标值,返回 -1return -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;}
};