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

相关推荐
xiaoshiguang330 分钟前
LeetCode:77. 组合
java·算法·leetcode
测试杂货铺5 小时前
Jmeter随机参数各种搭配
自动化测试·软件测试·python·测试工具·jmeter·职场和发展·测试用例
今天吃饺子6 小时前
小创新模型!6种2024算法优化BiTCN-SVM单变量输入单步预测,MATLAB机器学习预测全家桶再更新...
人工智能·算法·机器学习·支持向量机·matlab
廖显东-ShirDon 讲编程6 小时前
《零基础Go语言算法实战》【题目 2-5】函数参数的值传递和引用传递
算法·程序员·go语言·web编程·go web
不玩return的马可乐6 小时前
LeetCode 747. 至少是其他数字两倍的最大数
数据结构·c++·程序人生·算法·leetcode
bgf_me7 小时前
代码随想录算法训练营第三十二天|509.斐波那契数、70.爬楼梯、746.使用最小花费爬楼梯
算法
怎么名字都重复7 小时前
1.两数之和--力扣
java·数据结构·算法·leetcode·软件工程
Odaily_8 小时前
SVM赛道概览:MoveVM落地,SVM能走多远
人工智能·算法·机器学习·支持向量机·数据挖掘
深图智能8 小时前
OpenCV的一种改进型的素描特效算法
图像处理·opencv·算法·计算机视觉