「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战」
题目
给定一个 正整数 num ,编写一个函数,如果 num 是一个完全平方数,则返回 true ,否则返回 false 。
进阶:不要 使用任何内置的库函数,如 sqrt 。
实例1
输入: num = 16
输出: true
实例2
输入: num = 14
输出: false
思路分析
直接使用库函数自然是简单,不过也失去了做这道题的意义,做这道题不急,我们可以一点点优化。首先就是犯下了首先之罪的枚举。
bool isPerfectSquare(int num) {
for(int i = 1; i <= num; i ++){
if(i * i == num){
return true;
}
}
return false;
}
很遗憾,由于int溢出而出现了错误。
bool isPerfectSquare(int num) {
for(long i = 1; i <= num; i ++){
if(i * i == num){
return true;
}
}
return false;
}
然而这样会造成超时,所以O(N)并不好用,那么除了由于乘数为2时,另一个乘数一定小于等于n/2,那么我们就可以利用这一条将他变为
bool isPerfectSquare(int num) {
for(long i = 2; i <= num/2; i ++){
if(i * i == num){
return true;
}
}
return num == 1;
}
但是这样其实还是浪费时间,进一步利用这个性质去通过让双指针不断逼近的方式来找到最优解
bool isPerfectSquare(int num) {
int p = 1, q = num;
while(p < q){
p++;
q = num / p;
}
return p == q && p * q == num;
}
这样只需要不断判断是否p<q的方式让两个指针不断逼近,当不满足这个条件时比较pq是否相等以及p * q是否等于num
这种方法的时间复杂度是根号n,我们还可以用二分解决这个问题。
bool isPerfectSquare(int num) {
int p = 0, q = num;
while(p < q){
long mid = (p + q) / 2;
cout << mid;
if (mid * mid == num)return true;
else if (mid * mid > num){
q = mid - 1;
}else {
p = mid + 1;
}
}
return p == q && p * q == num;
}
许久不用二分,甚至有些生疏,在三个if里面写了个死循环。。。