题源: 704. 二分查找
思路
-
初始化边界:初始化
l
为-1和r
为nums.size()
。我们定义 target 是在一个在左开右开的区间里,避免记混r和l应该更新为mid还是mid + 1。这样一来,r和l就都更新为mid了。 -
二分查找循环:
-
循环条件是
l + 1 != r
,意味着两个指针之间至少有一个元素。 -
计算中点
mid
为(l + r) / 2
,这样可以避免整数溢出的风险。 -
根据
nums[mid]
与target
的比较,更新搜索边界:-
如果
nums[mid] > target
,说明目标值在左半部分,更新r = mid
。 -
如果
nums[mid] < target
,说明目标值在右半部分,更新l = mid
。 -
如果
nums[mid] == target
,找到目标值,返回mid
。
-
-
-
搜索结束:如果退出循环,说明没有找到目标值,返回-1。
复杂度
时间复杂度:
- O(log n):每次循环中点
mid
将搜索区间减半,因此时间复杂度为对数级别,即log2(n)
,其中n
是数组nums
的长度。
空间复杂度:
- O(1):该算法仅使用了固定数量的额外空间(几个变量
l
、r
和mid
),因此空间复杂度为常量级。
特别注意:
- 这种实现方式使用
l
和r
作为开区间的边界,使得r
始终指向一个无效的超出数组的位置,而l
初始为一个无效的负位置。这种方法在处理边界时更加简洁,但需要对边界条件处理得当,以避免越界或漏检错误。
代码模板:
class Solution {
public:
int search(vector<int>& nums, int target) {
int l = -1, r = nums.size();
while(l + 1!= r){
int mid = l + (r - l)/2;
if(nums[mid] > target) r = mid;
else if(nums[mid] < target) l = mid;
else return mid;
}
return -1;
}
};