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

相关推荐
椰羊~王小美38 分钟前
LeetCode -- Flora -- edit 2025-04-27
算法·leetcode·职场和发展
缘友一世2 小时前
从线性回归到逻辑回归
算法·逻辑回归·线性回归
前端_学习之路2 小时前
javaScript--数据结构和算法
javascript·数据结构·算法
迷路的小绅士2 小时前
计算机网络核心知识点全解析(面试通关版)
计算机网络·面试·职场和发展
weixin_428498493 小时前
使用HYPRE库并行装配IJ稀疏矩阵指南: 矩阵预分配和重复利用
算法·矩阵
雾削木5 小时前
mAh 与 Wh:电量单位的深度解析
开发语言·c++·单片机·嵌入式硬件·算法·电脑
__lost5 小时前
小球在摆线上下落的物理过程MATLAB代码
开发语言·算法·matlab
中小企业实战军师刘孙亮5 小时前
实体店的小程序转型之路:拥抱新零售的密码-中小企实战运营和营销工作室博客
职场和发展·小程序·创业创新·学习方法·业界资讯·零售·内容运营
mit6.8246 小时前
[Lc_week] 447 | 155 | Q1 | hash | pair {}调用
算法·leetcode·哈希算法·散列表
jerry6097 小时前
优先队列、堆笔记(算法第四版)
java·笔记·算法