基本思路是二分查找,只是判断标准变为x^2 ?= key
改进思路是缩小二分查找的起始区间,步骤如下:
- 设被查找数为N,令A = 1,B = N
- 每次令 A *= 2, B /= 2,直到A >= B停止
- 此时,若A == B,则N是A的平方;若A > B,则二分查找的初始区间为[B, A]
- 若二分查找失败,则N不是某个自然数的平方
改进思路的证明:假设存在K,使得2^K >= N/(2^K),对不等式两边乘以2^K,得到(2^K)^2 >= N,即2^K >= sqrt(N),2^K即为A;再对上述结论两边取倒数,得1/(2^K) <= 1/sqrt(N),分母有理化得1/(2^K) <= sqrt(N)/N,不等式两边乘以N得N/(2^k) <= sqrt(N),N/(2^K)即为B。综上,有N/(2^K) <= sqrt(N) <= 2^K,用语言描述即N的平方根若存在,必然在区间[B, A]中
代码如下:
int is_square(int n){
assert(n > 0);
int low = 1, high = n, mid;
while(low < high){
low <<= 2;
high >>= 2;
}
if(low != high){
low ^= high;
high ^= low;
low ^= high;
while(low <= high){
mid = low + (high-low)/2;
if(mid*mid < n)
low = mid+1;
else if(mid*mid > n)
high = mid-1;
else
return mid; //存在某自然数是N的平方,成功
}
return -1; //二分查找失败,不存在
}
else
return low; //成功
}