问题:有效的完全平方数
给定一个正整数 num ,编写一个函数,如果 num 是一个完全平方数,则返回 true ,否则返回 false 。
进阶:不要 使用任何内置的库函数,如 sqrt 。
来源:力扣(LeetCode)
思路一:暴力遍历求解
对小于num的整数从1开始遍历,判断平方是否等于num,若等于则返回true,否则返回false。
class Solution {
public boolean isPerfectSquare(int num) {
boolean result = false;
if (num==1) result = true;
for(int i=2; i < num/2+1; i++){
if(i*i==num){
result = true;
break;
}
}
return result;
}
}
缺点:整数过大时,超出时间限制。
思路二:二分法
- 一个完全平方数的根x,一定满足 1 ≤ x ≤ n u m 1 \le x \le num 1≤x≤num,我们将此区间作为搜寻区间。
- left从区间左侧开始,right从区间右侧开始,计算中间数 m i d = ( l e f t + r i g h t ) 2 mid=\frac{(left+right)}{2} mid=2(left+right)
- 完全平方跟x一定满足三种关系之一, m i d = = x , m i d < x , m i d > x mid ==x ,mid <x, mid>x mid==x,mid<x,mid>x,故以此作为left或right的更新条件。
- 二分法相比暴力求解法,一定程度上降低了时间复杂度。
class Solution {
public boolean isPerfectSquare(int num) {
int left = 0;
int right = num;
boolean result = false;
while (left <= right){
int mid = (left + right)/2;
long mid_square = (long)mid*mid;
if(mid_square < num){
left = mid + 1;
}else if(mid_square > num){
right = mid - 1;
}
else{
result = true;
return result;
}
}
return result;
}
}
思路三:牛顿法
牛顿法是近似求解函数零点的方法,其迭代思路如下。
对于函数
f
(
x
)
f(x)
f(x),任取起始点
(
x
0
,
f
(
x
0
)
)
(x0,f(x0))
(x0,f(x0)),过该点做函数
f
(
x
)
f(x)
f(x)的切线,切线与x轴交点
x
1
x1
x1即为下次更新的点的横坐标,相比
x
0
x0
x0而言,
x
1
x1
x1距离零点更近,经过多次迭代后,可近似认为点
x
1
x1
x1逼近函数零点。
思路:
在这个问题中
f
(
x
)
=
x
2
−
n
u
m
f(x)=x^2-num
f(x)=x2−num
更新公式
x
i
+
1
=
(
x
i
+
n
u
m
/
x
i
)
/
2
x_{i+1}=(x_i+num/{x_i})/2
xi+1=(xi+num/xi)/2
结束条件:我们认为相邻两次迭代结果相近时,就可以认为足够接近零点。
代码:
class Solution {
public boolean isPerfectSquare(int num) {
double x0 = num;
double x1 = 0;
while (true){
x1 = (x0 + num/x0)/2;
if (x0 - x1 < 1e-1)
break;
x0 = x1;
}
x1 = (int)x1;
return x1*x1 == num;
}
}
参考:力扣官方题解