在有序数组中查找目标数值并返回下标,若不存在返回-1
int search(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid; // 找到目标,直接返回索引
} else if (nums[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1; // 未找到目标,返回 -1
}
二分查找很常见的一个算法,但真写起来需要注意的细节还挺多的
-
while (left <= right) 这里控制循环继续的条件是“<=”而不是“<”,因为后者会在恰好最后才找到目标值的情境下查找失败
-
int mid = left + (right - left) / 2;计算mid时使用这种差值计算的方法而不是使用 (right + left) / 2这种方法,因为当数组很长的时候left+right可能会越界
-
因为在数组中元素各不相同的情景下每个数都是唯一的,就不需要考虑当num[mid]==target时的收缩方向只需要直接返回就可以了
在有序数组中查找目标值,目标值可能有多个,返回它的边界索引,即[left,right],若不存在返回[-1,-1]
可以分别二分查找目标值的左右边界
int findLeft(const vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] >= target) {
right = mid - 1; // 继续在左半部分查找
} else {
left = mid + 1;
}
}
// 检查 left 是否越界以及是否等于 target
if (left >= nums.size() || nums[left] != target) {
return -1;
}
return left;
}
int findRight(const vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] <= target) {
left = mid + 1; // 继续在右半部分查找
} else {
right = mid - 1;
}
}
// 检查 right 是否越界以及是否等于 target
if (right < 0 || nums[right] != target) {
return -1;
}
return right;
}
以查找左边界的函数findLeft举例,需要注意的几个细节:
-
当 nums[mid] >= target 时 right = mid - 1 表示当nums[mid] == target 时不会直接返回mid,因为mid很可能不是边界值,并且因为该函数是求左边界所以调整right,最后可能的左边界的索引就是left了
-
在返回时需要判断left是否越界以及left处的值是否是target
搜索螺旋排序数组
这不是一个正常的有序数组,它由两段有序的部分组成,在二分查找时需要考虑left和mid是否处于同一个有序部分
int search(vector<int>& nums, int target) {
int left = 0, right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
// 如果找到目标值,直接返回其下标
if (nums[mid] == target) {
return mid;
}
if (nums[left] <= nums[mid]) {
if (nums[left] <= target && target < nums[mid]) {
right = mid - 1;
} else {
left = mid + 1;
}
}else {
if (nums[mid] < target && target <= nums[right]) {
left = mid + 1;
} else {
right = mid - 1;
}
}
}
// 未找到目标值
return -1;
}
-
nums[left] <= nums[mid]说明left和mid处于同一段有序部分,left和mid这一段是有序的,当target处于这段之中,更新right
-
同理当nums[left] > nums[mid] 时,说明mid和right处于同一段有序部分,mid和right是有序的,当target处于这一段时,更新left