题目描述
给定一个正整数 num,编写一个函数,如果 num 是一个完全平方数,则返回 True,否则返回 False。
说明:不要使用任何内置的库函数,如 sqrt。
示例 1:
输入:16
输出:True
示例 2:
输入:14
输出:False
一、等差数列法
根据等差数列公式:1+3+5+…+(2n-1)=n^2
因此任意一个平方数可以表示成这样的奇数序列和。
具体代码实现如下:
class Solution {
public:
bool isPerfectSquare(int num) {
if(num < 2) return true;
int sub=1;
while(num > 0) {
num -= sub;
sub += 2;
}
return num == 0;
}
};
复杂度分析
- 时间复杂度:O(sqrt(N))。
- 空间复杂度:O(1)。
AC结果
二、 二分法
1.若 num < 2,返回 true。
2.设置左边界L为 2,右边界R为 num/2。
3.当 L <= R时:令 x = L + (R-L)/2 作为一个猜测,计算当前猜测值的平方tmp = x * x ,并与 num做比较:
- 如果 tmp > num, 设置左边界 L = x+1;
- 如果 tmp > num ,设置右边界 R = x-1;
- 否则 num 是一个完全平方数,返回 true。
4.如果在循环体内没有找到,则说明 num 不是完全平方数,返回 false。
class Solution {
public:
bool isPerfectSquare(int num) {
if(num < 2) return true;
long L=2,R=num/2,mid=0;
while(L<=R) {
mid = L + (R-L)/2;
if(mid * mid > num) R = mid-1;
else if(mid * mid < num) L = mid+1;
else return true;
}
return false;
}
};
复杂度分析
- 时间复杂度:O(logN)。
- 空间复杂度:O(1)。
AC结果
三、牛顿迭代法
牛顿迭代法的思想是从一个初始近似值开始,进行一系列改进,进而逼近根的过程。
那么如何从初始近似值逼近根呢?下面给出粗略的推导公式:
解题步骤:
1.首先取num/2作为初始近似值。
2.当 x * x > num时,用牛顿迭代法取计算下一个近似值:x=(x+num/x)/2。
3.循环执行步骤2直至跳出循环,返回 x*x == num。
class Solution {
public:
bool isPerfectSquare(int num) {
if(num < 2) return true;
long tmp = num >> 1;
while(tmp*tmp > num)
tmp = (tmp + num/tmp) >> 1;
return tmp*tmp == num;
}
};
复杂度分析
- 时间复杂度:O(logN)。
- 空间复杂度:O(1)。
AC结果