二分法时间复杂度为O(logn),主要思想就是不断缩小区间范围,最后找到要找的那个数。
- 第一步:首先找到中间位置,即左边界、右边界的和除以2
- 第二步:判断要的数位于那个区间,如果在左边界和中间位置之间,那么右边界就要移到中间位置;如果在右边界和中间位置之间,那么左边界就要移到中间位置
- 第三步:再次确定中间位置,重复1,2步,直到找到要找的那个数
vector<int> v(5);
int right=4,left=0;
while(left<right)
{
int mid=(left+right)>>1;
if(v[mid]<x)
left=mid+1;
else
right=mid;
...
}
return v[left]
但是二分法最后还有个关键点,就是边界问题,如果大了可能死循环,如果小了可能漏掉要找的那个数,下面我们严谨的看看这个边界逻辑;
就比如上面的代码,left=mid+1,为什么right=mid,不是right=mid-1其实我们仔细想也能想到,如果right=mid-1就可能漏掉我们要找的数,比如1 2 3 4 5 ,我们要找到3,第一次mid可以找到3,大于等于3即x,所以应该向左边靠,如果right=mid-1,right就到了2的位置,第二次mid将会找到1, 1<3然后向右靠,left最后没有找到3,而是到了2,退出循环;但是right=mid,第一次mid也是找到3,然后right到了3的位置,第二次mid找到2,2<3然后left到了3的位置,最后一次找到3,退出循环,left最后就是等于3。
当然如果执意想用right=mid-1也可以,就需要在循环中加入mid==x即我们要找的那个数就返回,x循环提交也需要改一下,保证不漏掉数,不如正好mid=left=right这种情况,最后其实不用返回v[left]了,因为循环内已经有返回了,如下:
vector<int> v(5);
int right=4,left=0;
while(left<=right)
{
int mid=(left+right)>>1;
if(v[mid]==x) return v[mid];
if(...)
left=mid+1;
else
right=mid-1;
...
}
return -1;
当然如果数组中肯定有要找的数,那么可直接改条件即可:
vector<int> v(5);
int right=4,left=0;
while(left<=right)
{
int mid=(left+right)>>1;
if(...)
left=mid+1;
else
right=mid-1;
...
}
return v[left]
其他的办法也可以,只要不漏掉数就可以