本文参考《labuladong的算法小抄》
二分查找适用于在一个排序数组中找到给定的数,遍历的复杂度为O(n), 二分的复杂度为O(logn),二分的场景有以下三种:
- 寻找一个数
- 寻找左侧边界
- 寻找右侧边界
!!关于搜索区间[left, right)和[left, right] !!
开区间的话就像STL中的迭代器(指向最后一个元素的下一个元素),因此right=nums.size(), 对于mid的赋值同理,搜索过就要缩小区间(因此left向右移动要mid+1(左闭), right向左移动不用变(右开))。闭区间和开区间同理。
1.基本二分搜索框架–闭区间[left, right]
int binarySearch(vector<int> nums, int target) {
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left)>>1;
if (nums[mid] == target) return mid;
else if (nums[mid] > target) right = mid - 1;
else if (nums[mid] < target) left = mid + 1;
}
return -1;
}
都使用else if 结构列清楚三种情况(等于小于大于),写完可以尝试化简。
2.寻找左侧边界的二分搜索框架–常见左闭右开区间[left, right)
int binarySearch(vector<int> nums, int target) {
int left = 0;
int right = nums.size();
while (left < right) {
int mid = left + (right - left) >> 1;
if (nums[mid] == target) right = mid;
else if (nums[mid] < target) left = mid + 1;
else if (nums[mid] > target) right = mid;
}
if (left == nums.size()) return -1;
return nums[left] == target? left : -1;
}
3.寻找右侧边界的二分搜索框架–常见左闭右开区间[left, right)
int binarySearch(vector<int> nums, int target) {
int left = 0;
int right = nums.size();
while (left < right) {
int mid = left + (right - left)>>1;
if (nums[mid] == target) left = mid + 1;
else if (nums[mid] < target) left = mid + 1;
else if (nums[mid] > target) right = mid;
}
if (right == 0) return -1;
return nums[right - 1] == target? (right - 1): -1;
}
注意left的更新强制+1,因此迭代到最后倒数第二次left的值没有被检测到,要判定一次该值。
!!!统一搜索区间之后的代码:都是[left,right],非常重要!!!
1.基本二分查找
int binary_search(vector<int> nums, int target) {
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] < target) {
left = mid + 1;
}
}
return -1;
}
2.寻找左边界的二分查找
int binary_search(vector<int> nums, int target) {
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
right = mid - 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else if (nums[mid] < target) {
left = mid + 1;
}
}
if (left >= nums.size() || nums[left] != target) return -1;
return left;
}
3.寻找右侧边界的二分查找
int binary_search(vector<int> nums, int target) {
int left = 0;
int right = nums.size() - 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 if (nums[mid] < target) {
left = mid + 1;
}
}
if (right < 0 || nums[right] != target) return -1;
return right;
}