简介
二分法是一种基于有序序列的查找算法,时间复杂度是O(logn)。
二分区间
查找的时候首先要确定区间的类型,主要可以分为两种,左闭右闭[,]和左闭右开[,)(左开右闭同理)。区间的不同意味着边界的判断条件不同:缩小区间时候是取mid还是取mid-1,以及区间的合法性不同:左闭右闭left是可以等于right的,循环条件是while(left<=right),例:[1,1]合法,而左闭右开区间,如果相等[1,1)则是不合法的。
1.左闭右闭区间[left,right]:
int search(int* nums, int n, int target)
{
int left = 0;
int right = n-1;
int mid = 0;
while(left<=right) {
mid = (left+right)/2;
if(nums[mid] > target) {
right = mid-1;
}
else if(nums[mid] < target) {
left = mid+1;
}
else if(nums[mid] == target){
return mid;
}
}
return -1;
}
2.左闭右开区间[left,right)
int search(int* nums, int n, int target)
{
int left = 0;
int right = n;
int mid = 0;
while(left < right){
int mid = left + (right - left) / 2;
if(nums[mid] < target){
left = mid + 1;
}else if(nums[mid] > target){
right = mid ;
}else{
return mid;
}
}
return -1;
}
注意
- 有序序列中不能有重复元素,否则二分查找的返回值不唯一;
- 左闭右开区间右边界取的是n不是n-1;
mid = (left+right)/2;
这句如果数组较大,上界超出了int型数据范围的一半,在查找到数组的后半段的时候可能溢出,可以用int mid = left + (right - left) / 2;
来代替避免溢出;- 如果题目问的是目标值在不在区间里面,可以用左闭右闭区间查找,找到了就返回目标值下标或者输出,没找到就返回-1;如果题目问的是找到第一个大于/小于目标值的下标,就用左闭右开区间,判断小于等于和大于,循环结束时的右边界就是第一个大于目标值的下标。