普通的二分查找
先引入一个最简单的二分查找吧
int binarySearch(int* nums, int numsSize, int target){
int left = 0, right = numsSize-1;
while(left <= right){
int mid = left + (right - left)/2;
if(nums[mid] == target){
return mid;
}
else if(nums[mid] > target){
right = mid - 1;
}
else left = mid + 1;
}
return -1;
}
很明显,这么写法将每次执行的区间划分为
[left .....mid -1] (mid) [mid+1....right]
那换个写法呢(结果都是正确的)?
int binarySearch_2(int* nums, int numsSize, int target){
int left = 0, right = numsSize;
while(left < right){
int mid = left + (right - left)/2;
if(nums[mid] == target){
return mid;
}
else if(nums[mid] > target){
right = mid;
}
else left = mid + 1;
}
return -1;
}
这个写法将区间分为了左闭右开型,不同于上面的左右两边都是闭区间
[left....mid) (mid) [mid+1....right)
以上两个写法的while条件,一个是left <= right
,一个则是left < right
说明第一种while循环的结束条件为left > right
,第二种结束条件为left == right
其原因就是因为左闭右闭的区间[i, i]
是包含元素nums[i]
的,而左闭右开的区间[i, i)
相当于空集。
搞清楚while循环结束时的具体情况,对我们分析边界值非常重要。
当数组中存在多个目标值时,这种方法返回的是位于中间位置那个目标值的下标,但是如果我们想获得目标值第一次出现时的下标应该怎么办呢?
获取左侧边界的二分查找
int binarySearch_3(int *nums, int numsSize, int target){
int left = 0, right = numsSize - 1;
while(left <= right){
int mid = left + (right - left)/2;
if(nums[mid] == target){
right = mid - 1;
}
else if(nums[mid] > target){
right = mid - 1;
}
else left = mid + 1;
}
return nums[left] == target? left : -1;
}
此算法while循环的结束条件为left > right
,或者说是left = right + 1
,如果nums[left] == target
则说明我们最终找到了目标值,而且此时的left
是该目标值第一次出现的位置。这种也可以换成子区间左闭右开的写法
int binarySearch_4(int *nums, int numsSize, int target){
int left = 0, right = numsSize;
while(left < right){
int mid = left + (right - left)/2;
if(nums[mid] == target){
right = mid;
}
else if(nums[mid] > target){
right = mid;
}
else left = mid + 1;
}
return nums[left] == target? left : -1;
}
获取右侧边界的二分查找
原理同上,两种写法
int binarySearch_5(int *nums, int numsSize, int target){
int left = 0, right = numsSize-1;
while(left <= right){
int mid = left + (right - left)/2;
if(nums[mid] == target){
left = mid + 1;
}
else if(nums[mid] > target){
right = mid - 1;
}
else left = mid + 1;
}
return nums[right] == target? right : -1;
}
int binarySearch_6(int *nums, int numsSize, int target){
int left = 0, right = numsSize;
while(left < right){
int mid = left + (right - left)/2;
if(nums[mid] == target){
left = mid + 1;
}
else if(nums[mid] > target){
right = mid;
}
else left = mid + 1;
}
return nums[right-1] == target? right-1 : -1;
}
int main(){
int nums[6] = {1,2,2,2,3,5};
printf("binarySearch_1: %d\n", binarySearch_1(nums, 6, 2));
printf("binarySearch_2: %d\n", binarySearch_2(nums, 6, 2));
printf("binarySearch_3: %d\n", binarySearch_3(nums, 6, 2));
printf("binarySearch_4: %d\n", binarySearch_4(nums, 6, 2));
printf("binarySearch_5: %d\n", binarySearch_5(nums, 6, 2));
printf("binarySearch_6: %d\n", binarySearch_6(nums, 6, 2));
return 0;
}
“茴香豆”的“茴”字有四种写法,可这二分法有六种写法,孔乙己,得亏你生的早啊。
相关leetcode试题
find-first-and-last-position-of-element-in-sorted-array