Description
Given a positive integer num, write a function which returns True if num is a perfect square else False.
Example
Input: 16
Output: true
Input: 14
Output: false
Solution
二分查找法
最容易想到的一种方法便是二分查找法。例如,当num=64时,我们查看32的平方是否等于64,很明显应该大于,所以再查看16的平方是否等于64,再查看8的平方是否等于64,这时候是等于的,因此返回true。
使用二分查找法最重要的一点是要把middle写成long类型,因为当整型的middle值太大时,middle * middle
很有可能溢出。
public class Solution {
public boolean isPerfectSquare(int num) {
long lo = 1;
long hi = num;
long middle = lo + (hi - lo) / 2;
while(lo <= hi) {
long pow = middle * middle;
if(pow < num) {
lo = middle + 1;
} else if(pow > num) {
hi = middle - 1;
} else {
return true;
}
middle = lo + (hi - lo) / 2;
}
return false;
}
}
使用二分查找法的时间复杂度为O(logn)。
1+3+5…+n的数学规律
我们可以发现所有可以开平方的数都有为奇数相加这么一个特殊规律:
1: 1
4: 1+3
9: 1 + 3 + 5
16: 1 + 3 + 5 +7
25: 1 + 3 + 5 + 7 + 9
36: 1 + 3 + 5 + 7 + 9 + 11
...
因此我们要判断一个数是否可以开平方,可以将它不断的减去一个递增的奇数,直到其小于等于0。如果最后的结果等于0,说明其是由奇数组成的,也就是可以开平方的;否则,结果小于0,也就不能开平方。
因为平方根为6的数要相减6次,平方根为5的数要相减5次,以此类推可以得知这种解法的时间复杂度为O(sqrt(num))。
牛顿迭代法
知乎上有对牛顿迭代法进行较好的解释:
这里对牛顿迭代公式进行进一步化简:
public class Solution3 {
public boolean isPerfectSquare(int num) {
long x = num;
while (x * x > num) {
x = (x + num / x) / 2;
}
return x * x == num;
}
}