二分查找的思想很简单,但具体使用时如何快速准确套用"公式"解决二分查找类型的问题呢?
首先考虑最简单的情况,假如有一个由False和True组成的序列:
[True True True True True True False False False]
如何快速用二分查找找到第一个False?方法如下:
int low = 0;
int high = 8;//数组维度下标
while(low < high)
{
int mid = (low + high)/2;
if(array[mid] == True)
{
low = mid + 1;
}
else
{
high = mid;
}
}
或者这样的序列,需要找到第一个True,解法类似:
[False False False False False False True True True]
int low = 0;
int high = 8;//数组维度下标
while(low < high)
{
int mid = (low + high)/2;
if(array[mid] == False)
{
low = mid + 1;
}
else
{
high = mid;
}
}
那么不管对于什么类型的问题,我们只需要构造出这样的序列,再套用如上模式就可以解决问题。
举个例子:求正整数x的平方根,保留平方根整数部分。
0 -> 0 //大于等于0的平方,小于1的平方
1、2、3 -> 1 //大于等于1的平方,小于2的平方
4、5、6、7 -> 2//大于等于2的平方,小于3的平方
根据以上事实,我们需要找到整数x第一个小于的整数y的平方,那么将(y-1)就是解。
我们只考虑较简单的情况,假设x的平方根在0-1000范围内。
int low = 0;
int high = 1000;
while(low < high)
{
int mid = (low + high)/2;
if(condition(mid,x))
{
low = mid + 1;
}
else
{
high = mid;
}
}
公式套用就是这样,但我们需要构造出condition(mid,x)条件来。
假设x=14,如果将条件设为x >= n*n,那么形成如下序列:
[x>=0*0 x>=1*1 x>=2*2 x>=3*3 x>=4*4] ->
[x>=0 x>=1 x>=4 x>=9 x>=16] ->
[True True True True False] ->
也就是说condition(mid,x)设为 x >= mid*mid之后,找满足条件序列的第一个False
带入上述模式最终代码如下:
int low = 0;
int high = 1000;
while(low < high)
{
int mid = (low + high)/2;
if( (x >= mid * mid) == True)//condition(mid,x), == True只是为了与模式代码统一
{
low = mid + 1;
}
else
{
high = mid;
}
}
我们也可以构造不同的条件:
假设x=14,如果将条件设为x < n*n,那么形成如下序列:
[x<0*0 x<1*1 x<2*2 x<3*3 x<4*4] ->
[x<0 x<1 x<4 x<9 x<16] ->
[False False False False True] ->
套用后代码如下:
int low = 0;
int high = 1000;
while(low < high)
{
int mid = (low + high)/2;
if( (x < mid * mid) == False)//condition(mid,x) == False只是为了与模式代码统一
{
low = mid + 1;
}
else
{
high = mid;
}
}
其他情况大致也可以套用如上框架。