Given a positive integer num, write a function which returns True if num is a perfect square else False.
Note: Do not use any built-in library function such as sqrt.
Example 1:
Input: 16 Returns: True
Example 2:
Input: 14 Returns: False
给定一个正数,判断其是否是完全平方数,要求不用sqrt。
这道题比较简单,问题是效率。
法一:从1枚举到num/2,虽然肯定是正确的,但是效率太低了通不过。
代码如下:
bool isPerfectSquare(int num)
{
if (num == 1)
return true;
for (int i = 0; i <= num / 2; i++)
{
int tmp = i*i;
if (tmp == num)
return true;
if (tmp > num)
break;
}
return false;
}
法二:法一效率低是因为枚举的范围太广了,输入num很小时还好,num很大时,比如INT_MAX时,简直是灾难!可考虑如何缩小这个范围。对于[1,num]之间的任一个数k1,若k12>num,显示[k1,num]之间的数的平方都会大于num,不需考虑;若k22<num,显然[1,k2]之间的数的平方都会小于num,也不需要考虑。若num是完全平方数,其根必然处于(k1,k2)这个区间。如果能快速确定这个区间,并使这个区间的范围尽可能小,执行效率就能明显得到改善。在此我们可以考虑首先取num的一半,即k=num/2,若k2>num,则k缩小一倍,即k/=2,一直到k2<num,若num是完全平方数,则其根在(k,2k)范围内。此方法可通过。
代码如下:
bool isPerfectSquare(int num)
{
if (num == 1)
return true;
long long k = num / 2, val = 0;
while (true)
{
val = k*k;
if (val == num)
return true;
if (val < num)
break;
k /= 2;
}
for (long long i = k + 1; i < k * 2; i++)
{
val = i*i;
if (val == num)
return true;
if (val > num)
break;
}
return false;
}
法三:此外,想到常用的二分法,居然也是超时通不过。
代码如下:
bool isPerfectSquare(int num)
{
int left = 0, right = num, mid = 0, tmp = 0;
while (left <= right)
{
mid = (left + right) / 2;
tmp = mid*mid;
if (tmp == num)
return true;
if (tmp < num)
left = mid + 1;
else
right = mid - 1;
}
return false;
}
法四:二分法能不过的原因还是对于大一点的数,查找的范围太广了。可结合方法二,先将查找范围确定在(k,2k),再使用二分法,显然对于比较大的数,执行效率将比法二高得多。此法亦能通过。
代码如下:
bool isPerfectSquare(int num)
{
if (num == 1)
return true;
long long k = num / 2, val = 0;
while (true)
{
val = k*k;
if (val == num)
return true;
if (val < num)
break;
k /= 2;
}
long long left = k, right = k * 2, mid = 0;
while (left <= right)
{
mid = (left + right) / 2;
val = mid*mid;
if (val == num)
return true;
if (val < num)
left = mid + 1;
else
right = mid - 1;
}
return false;
}
浙公网安备 33010602011771号