704. 二分查找
题目链接
分析:有序数组,且无重复元素
解题思路:
1. 遍历:
for循环遍历数组,逐个比对若数组元素等于目标值,则返回下标;若循环结束后都未找到目标值。则返回-1
int search(vector<int>& nums, int target) {
int i = 0;
for(i = 0; i < nums.size(); i++){
if(nums[i] == target){
return i;
}
}
return -1;
}
2. 二分查找:
- 关键点1:数组区间定义:左闭右闭(right = num.size()-1)、左闭右开(right = num.size())、左开右闭(区间定义影响while循环的判别条件)
- 关键点2:循环判断使用的区间是否是合法区间:区间值左右边界的数值大小的判断<=和<
是否写等号取决于left=right在区间上是否合法(左闭右闭合法,其他不合法) - 关键点3:middle的计算:middle、middle-1
是否-1或+1取决于当前区间是否已包含middle值,包含则在做条件判断是已确定middle必然不等于middle,因此使用+1、-1
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0; //区间定义
int right = nums.size() - 1;
while(left <= right){ //区间合法性判断
int middle = left + ((right - left) / 2);
if(nums[middle] == target){
return middle;
}else if(nums[middle] < target){
left = middle + 1; //新区间边界的取值
}else{
right = middle - 1;
}
}
return -1;
}
};
35. 搜索插入位置
解题思路:
题目条件:无重复元素的有序数组
- 基于经典的二分查找[[704. 二分查找]]求解
- 应返回的插入位置分析:
循环结束的条件为left>right,此时有两种可能性:1. nums[middle]<target,则插入位置为middle+1,反之插入位置为middle;
int searchInsert(vector<int>& nums, int target) {
int left = 0;
int right = nums.size()-1;
int middle = 0;
while(left <= right){
middle = left + (right-left)/2;
if(nums[middle] == target){
return middle;
}else if(nums[middle] < target){
left = middle + 1;
}else{
right = middle -1;
}
}
if(nums[middle] > target){ //应返回的插入位置判断
return middle;
}else{
return middle + 1;
}
}
34. 在排序数组中查找元素的第一个和最后一个位置
解题思路
题目条件:升序排列数组、数组元素有重复,要求算法复杂度为O(logn)
- 考虑使用二分法分别查找左右边界
- 可能情况讨论:
- 找到:Target在数组范围内,且存在
- 未找到:Target不在数组范围内 | 在数组范围内但不存在
class Solution {
public:
int getRightBorder(vector<int>& nums, int target){
int left = 0;
int right = nums.size()-1;
int rightBorder = -2; //假设右边界不在数组范围内
while(left <= right){
int middle = left + ((right - left) / 2);
if(nums[middle] > target){
right = middle - 1;
}else{
left = middle + 1;
rightBorder = left;
}
}
return rightBorder;
}
int getLeftBorder(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int leftBorder = -2;
while (left <= right) {
int middle = left + ((right - left) / 2);
if (nums[middle] >= target) {
right = middle - 1;
leftBorder = right;
} else {
left = middle + 1;
}
}
return leftBorder;
}
vector<int> searchRange(vector<int>& nums, int target) {
int leftBorder = getLeftBorder(nums, target);
int rightBorder = getRightBorder(nums, target);
// 情况一
if (leftBorder == -2 || rightBorder == -2){
return {-1, -1};
}
// 情况三
if (rightBorder - leftBorder > 1){
return {leftBorder + 1, rightBorder - 1};
}
// 情况二
return {-1, -1};
}
};