二分查找
二分查找指在有序数组中,每次排除一半的可能性,查找剩下的范围中符合条件的值。
- 二分:排除一半,选择一半
- 有序:数据必须有序
- 边界处理:left < right 还是 left <= right?left = mid + 1 还是 left = mid?
题单
| 阶段 | 顺序 | 题目 | 难度 | 核心训练 |
|---|---|---|---|---|
| 基础模板 | 1 | Binary Search (LeetCode 704) | ⭐ | 标准二分模板,找 target |
| 基础模板 | 2 | Search Insert Position (LeetCode 35) | ⭐ | 找不到时返回插入位置 |
| 基础模板 | 3 | First Bad Version (LeetCode 278) | ⭐ | 单调性、找第一个满足条件的位置 |
| 边界控制 | 4 | Find First and Last Position (LeetCode 34) | ⭐⭐ | 左边界 / 右边界 |
| 边界控制 | 5 | Sqrt(x) (LeetCode 69) | ⭐⭐ | 找满足条件的最大值 |
| 边界控制 | 6 | Valid Perfect Square (LeetCode 367) | ⭐⭐ | 边界判断、防溢出 |
| 旋转数组 | 7 | Find Minimum in Rotated Sorted Array (LeetCode 153) | ⭐⭐⭐ | 旋转数组入门,局部有序 |
| 旋转数组 | 8 | Search in Rotated Sorted Array (LeetCode 33) | ⭐⭐⭐ | 在旋转数组中找 target |
| 旋转数组 | 9 | Search in Rotated Sorted Array II (LeetCode 81) | ⭐⭐⭐⭐ | 含重复元素的旋转数组 |
| 答案二分 | 10 | Koko Eating Bananas (LeetCode 875) | ⭐⭐⭐⭐ | 二分答案模板 |
| 答案二分 | 11 | Capacity To Ship Packages Within D Days (LeetCode 1011) | ⭐⭐⭐⭐ | 复杂 check 函数 |
模板
| 区间语义 | 区间表示 | right 初始值 |
right 是否参与搜索 |
循环条件 | 退出条件 | left == right 时 |
|---|---|---|---|---|---|---|
| 闭区间 | [left, right] |
len - 1 |
是 | left <= right |
left > right |
仍有 1 个元素 |
| 左闭右开 | [left, right) |
len |
否 | left < right |
left == right |
区间为空 |
704
入门题目,本方法基于left<=right和闭区间思考得来。
cpp
class Solution {
public:
int search(vector<int>& nums, int target) {
int n = nums.size();
int left = 0;
int right = n-1;
while(left<=right){
int mid = left+(right-left)/2;
if(nums[mid]>target){
right = mid -1;
}else if(nums[mid]<target){
left = mid +1;
}else{
return mid;
}
}
return -1;
}
};
35
cpp
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int n = nums.size();
int left = 0;
int right = n-1;
while(left<right){
int mid = left+(right-left)/2;
if(nums[mid] > target){
right = mid -1;
}else if(nums[mid] < target){
left = mid +1;
}else{
return mid;
}
}
return nums[left]>= target? left :left+1;
}
};
278
cpp
// The API isBadVersion is defined for you.
// bool isBadVersion(int version);
class Solution {
public:
int firstBadVersion(int n) {
int left = 1;
int right = n;
while(left <= right){
int mid = left+(right-left)/2;
if(isBadVersion(mid)){
right = mid - 1;
}else{
left = mid + 1;
}
}
return left ;
}
};
34
69
cpp
class Solution {
public:
int mySqrt(int x) {
int left = 0;
int right = x;
while(left<=right){
int mid = left +(right-left)/2;
long long sqrt ;
sqrt = (long long )mid * mid;
if(sqrt > x){
right = mid - 1;
}else if (sqrt < x){
left = mid + 1;
}else{
return mid;
}
}
return right;
}
};