LeetCode 第367题:有效的完全平方数

题目描述

给定一个正整数 num,判断它是否是一个完全平方数。即是否存在一个整数 x,使得 x 2 = num x^2 = \text{num} x2=num。

解法思路

我们可以采用以下几种常见的方法来判断是否为完全平方数:

  1. 二分查找法 :通过二分查找找到一个整数 x,使得 x 2 = num x^2 = \text{num} x2=num,若找到了就返回 true
  2. 牛顿法:通过迭代方式逼近平方根。
  3. 数学方法:不断减去奇数,直到剩下的数为零。

在这篇文章中,我们将使用 二分查找法 来实现解决方案,因为它具有较好的时间复杂度和简洁性。

二分查找法

由于 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;
    }
  • 这部分代码处理了特殊情况:01 都是完全平方数。因此如果 num01,直接返回 true
c 复制代码
    // 设置二分查找的左右边界
    int left = 1, right = num / 2;
  • 设置二分查找的边界:
    • 左边界 left = 1,因为 01 已经被单独处理过。
    • 右边界 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),其中 nnum 的大小。每次我们将搜索范围缩小一半,直到找到目标。

  • 空间复杂度 :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),适用于较大的整数输入。希望本篇文章能够帮助你掌握这道题目的解决方案!如果你有任何问题或改进意见,欢迎在评论区留言。

相关推荐
_Itachi__1 分钟前
LeetCode 热题 100 206. 反转链表
算法·leetcode·链表
南宫生40 分钟前
力扣每日一题【算法学习day.130】
java·学习·算法·leetcode
柠石榴41 分钟前
【练习】【类似于子集问题】力扣491. 非递减子序列/递增子序列
c++·算法·leetcode·回溯
干饭高手1 小时前
Day9,Hot100(图论)
python·leetcode·图论
!!!5251 小时前
Java实现斗地主-做牌以及对牌排序
java·算法
sjsjs111 小时前
【数据结构-并查集】力扣1722. 执行交换操作后的最小汉明距离
数据结构·算法·leetcode
CoderIsArt1 小时前
生成一个立方体贴图(Cube Map)
算法·sharpgl
且听风吟ayan1 小时前
leetcode day20 滑动窗口209+904
算法·leetcode·c#
m0_675988231 小时前
Leetcode350:两个数组的交集 II
算法·leetcode·数组·哈希表·python3
_Itachi__1 小时前
LeetCode 热题 100 160. 相交链表
算法·leetcode·链表