二分查找 Binary Search
题目特征:有序数组查找元素,要求时间复杂度O(logN)。 分类:无重复数组查找某元素、有重复数组查找某元素左右边界
35. 搜索插入位置
34. 在排序数组中查找元素的第一个和最后一个位置
模板
int searchInsert(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) {
// 在右区间
left = mid + 1;
} else if (nums[mid] == target) {
return mid;
}
}
return -1;
}
框架说明
特例情况判断 while(left < right) 循环,结束后有left = right。 mid取值与数组个数为奇偶相关。 定位左侧元素时向下取整, mid = (left + right) / 2 ,向下取整时,可以保证左指针会变化, 定位右侧元素时向上取整, mid = (left + mid + 1) / 2 ,原因:向下取整时会出现左指针不移动的情况,无法跳出循环。 例: [5, 7, 7, 8, 8, 10] ; target = 8;
// 查找左边界时,当向下取整
left = 3, right = 5;
mid = (left + right ) /2 = 4;
nums[mid] == target --> left = mid = 4;
// 下一次循环有
mid = (4 + 5) / 2 = 4;
nums[mid] == target --> left = mid = 4;
...
// 无法跳出while
// 查找右边界时,改为向上取整
left = 3, right = 5;
mid = (left + right + 1) / 2 = 4;
nums[mid] == target --> left = mid = 4;
// 下一次循环
mid = (4 + 5 + 1) / 2 = 5;
nums[mid] > target --> right = mid - 1;
34. 在排序数组中查找元素的第一个和最后一个位置
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
// 特例
if (nums.size() == 0) {
return vector<int> {-1, -1};
}
// 查找左边界
int first = -1;
int left = 0;
int right = nums.size()-1;
while (left < right) {
int mid = (left + right) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] == target) {
right = mid;
} else {
right = mid - 1;
}
}
if (nums[left] == target) {
first = left;
} else {
return vector<int> {-1, -1};
}
// 查找右边界
int last = -1;
left = 0;
right = nums.size()-1;
while (left < right) {
int mid = (left + right + 1) / 2;
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] == target) {
left = mid;
} else {
right = mid - 1;
}
}
if (nums[left] == target) {
last = left;
}
return vector<int> {first, last};
}
};