题目描述
给定一个正整数 num
,判断它是否是一个完全平方数。即是否存在一个整数 x
,使得 x 2 = num x^2 = \text{num} x2=num。
解法思路
我们可以采用以下几种常见的方法来判断是否为完全平方数:
- 二分查找法 :通过二分查找找到一个整数
x
,使得 x 2 = num x^2 = \text{num} x2=num,若找到了就返回true
。 - 牛顿法:通过迭代方式逼近平方根。
- 数学方法:不断减去奇数,直到剩下的数为零。
在这篇文章中,我们将使用 二分查找法 来实现解决方案,因为它具有较好的时间复杂度和简洁性。
二分查找法
由于 x 2 x^2 x2 是一个单调递增的函数,我们可以通过二分查找来找到 x
,使得 x 2 = num x^2 = \text{num} x2=num。如果在查找过程中我们发现 x 2 = num x^2 = \text{num} x2=num,那么 num
就是完全平方数。如果没有找到,则 num
不是完全平方数。
C语言代码实现
c
#include <stdio.h>
#include <stdbool.h>
/**
* 判断一个数是否是完全平方数
* @param num: 要判断的整数
* @return: 如果 num 是完全平方数,则返回 true,否则返回 false
*/
bool isPerfectSquare(int num) {
// 特殊情况:0 和 1 是完全平方数
if (num == 0 || num == 1) {
return true;
}
// 设置二分查找的左右边界
int left = 1, right = num / 2;
// 使用二分查找
while (left <= right) {
int mid = left + (right - left) / 2;
int mid_square = mid * mid;
// 判断 mid 的平方是否等于 num
if (mid_square == num) {
return true; // 如果找到了完全平方数,返回 true
}
// 如果 mid 的平方小于 num,说明平方根在右半部分
else if (mid_square < num) {
left = mid + 1;
}
// 如果 mid 的平方大于 num,说明平方根在左半部分
else {
right = mid - 1;
}
}
// 如果没有找到完全平方数,返回 false
return false;
}
int main() {
// 测试用例
int test_cases[] = {16, 14, 25, 30, 1, 0, 144};
int num_tests = sizeof(test_cases) / sizeof(test_cases[0]);
for (int i = 0; i < num_tests; i++) {
int num = test_cases[i];
if (isPerfectSquare(num)) {
printf("%d is a perfect square.\n", num);
} else {
printf("%d is not a perfect square.\n", num);
}
}
return 0;
}
逐行解释代码
isPerfectSquare
函数
c
bool isPerfectSquare(int num) {
// 特殊情况:0 和 1 是完全平方数
if (num == 0 || num == 1) {
return true;
}
- 这部分代码处理了特殊情况:
0
和1
都是完全平方数。因此如果num
是0
或1
,直接返回true
。
c
// 设置二分查找的左右边界
int left = 1, right = num / 2;
- 设置二分查找的边界:
- 左边界
left = 1
,因为0
和1
已经被单独处理过。 - 右边界
right = num / 2
,因为num
的平方根最大值是num / 2
。例如,对于num = 16
,平方根最大值是4
。
- 左边界
c
// 使用二分查找
while (left <= right) {
int mid = left + (right - left) / 2;
int mid_square = mid * mid;
- 进入二分查找循环,在每次循环中计算中间值
mid
,并计算其平方mid_square = mid * mid
。- 使用
left + (right - left) / 2
来计算中间值,可以避免直接计算(left + right) / 2
可能导致的溢出。
- 使用
c
// 判断 mid 的平方是否等于 num
if (mid_square == num) {
return true; // 如果找到了完全平方数,返回 true
}
- 如果中间值
mid
的平方等于num
,那么num
是完全平方数,直接返回true
。
c
// 如果 mid 的平方小于 num,说明平方根在右半部分
else if (mid_square < num) {
left = mid + 1;
}
// 如果 mid 的平方大于 num,说明平方根在左半部分
else {
right = mid - 1;
}
}
- 如果
mid_square
小于num
,说明平方根应该在右半部分,因此将left
移动到mid + 1
。 - 如果
mid_square
大于num
,说明平方根应该在左半部分,因此将right
移动到mid - 1
。
c
// 如果没有找到完全平方数,返回 false
return false;
}
- 如果在二分查找中没有找到平方根,则返回
false
,说明num
不是完全平方数。
main
函数
c
int main() {
// 测试用例
int test_cases[] = {16, 14, 25, 30, 1, 0, 144};
int num_tests = sizeof(test_cases) / sizeof(test_cases[0]);
for (int i = 0; i < num_tests; i++) {
int num = test_cases[i];
if (isPerfectSquare(num)) {
printf("%d is a perfect square.\n", num);
} else {
printf("%d is not a perfect square.\n", num);
}
}
return 0;
}
- 在
main
函数中,我们创建了多个测试用例,包括完美的平方数和非完美的平方数。 - 通过
isPerfectSquare
函数判断每个测试用例,并输出相应的结果。
复杂度分析
-
时间复杂度 :二分查找的时间复杂度是 O(log n),其中
n
是num
的大小。每次我们将搜索范围缩小一半,直到找到目标。 -
空间复杂度 :O(1),仅使用了常数空间来保存
left
,right
, 和mid
等变量。
输出示例
16 is a perfect square.
14 is not a perfect square.
25 is a perfect square.
30 is not a perfect square.
1 is a perfect square.
0 is a perfect square.
144 is a perfect square.
总结
通过二分查找法,我们能够高效地判断一个数是否是完全平方数。该方法时间复杂度为 O(log n),适用于较大的整数输入。希望本篇文章能够帮助你掌握这道题目的解决方案!如果你有任何问题或改进意见,欢迎在评论区留言。