二分查找分为两种写法,第一种是左闭右闭区间,第二种是左闭右开区间
时间复杂度:O(log n),空间复杂度:O(1)
左闭右闭区间思路:
- 定义left,right两个坐标表示区间左右下标,因为右边是闭区间,所以right的值为nums.size()-1,恰好是最后一个元素的下标
- 循环条件为left<=right
- 计算中间middle坐标的值是否等于target
- 如果相等则返回middle坐标
- 如果不相等并且小于目标值(说明target在右半区间),移动left坐标至middle+1(middle本身已经检查过不等于target了,应该排除在外)
- 如果不相等并且大于目标值(说明target在左半区间),移动right坐标至middle-1(middle本身已经检查过不等于target了,应该排除在外)
- 直到left超出right(说明没有找到),返回-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) {
left = middle + 1;
}else if (nums[middle] > target) {
right = middle - 1;
}else
return middle;
}
return -1;
}
};
左闭右开区间思路:
- 定义left,right两个坐标表示区间左右下标,因为右边是开区间,所以right的值为nums.size(),如果是nums.size()-1会导致最后一个元素被排除在外
- 循环条件为left<right,right的值是一个取不到或者检查过的值,所以left没有等于right的必要
- 计算中间middle坐标的值是否等于target
- 如果相等则返回middle坐标
- 如果不相等并且小于目标值(说明target在右半区间),移动left坐标至middle+1(middle本身已经检查过不等于target了,应该排除在外)
- 如果不相等并且大于目标值(说明target在左半区间),移动right坐标至middle(middle本身已经检查过不等于target了,刚好可以当右边的开区间)
- 直到left超出right(说明没有找到),返回-1
左闭右开区间代码:
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size();
while (left < right) {
int middle = left + (right - left) / 2; // 防止数组下标越界
if (nums[middle] < target) {
left = middle + 1;
}else if (nums[middle] > target) {
right = middle;
}else
return middle;
}
return -1;
}
};