Swift - LeetCode - 有效的完全平方数

792 阅读1分钟

我正在参加「掘金·启航计划」

题目

给定一个 正整数 num,编写一个函数,如果 num 是一个完全平方数,则返回 true,否则返回 false

进阶:不要 使用任何内置的库函数,如 sqrt

示例 1:

  • 输入: num = 16
  • 输出: true

示例 2:

  • 输入: num = 14
  • 输出: false

方法一:使用内置的库函数

思路及解法

根据完全平方数的性质,我们只需要直接判断 num\textit{num} 的平方根 xx 是否为整数即可。对于不能判断浮点数的值是否等于整数的语言,则可以通过以下规则判断:

  • num \sqrt{\textit{num}} 为正整数,则有 xi2=(num)2=num\lfloor x_i \rfloor^2 = (\sqrt{\textit{num}})^2 = \textit{num},其中符号 x\lfloor x \rfloor 表示 xx 的向下取整。
class Solution {
    func isPerfectSquare(_ num: Int) -> Bool {
        let x: Int = Int(sqrt(Double(num)))
        return x * x == num
    }
}

复杂度分析

代码中使用的 pow\texttt{pow} 函数的时空复杂度与 CPU 支持的指令集相关,这里不深入分析。

方法二:暴力

思路及解法

如果 num\textit{num} 为完全平方数,那么一定存在正整数 xx 满足 x×x=numx \times x = \textit{num}。于是我们可以从 1 开始,从小到大遍历所有正整数,寻找是否存在满足 x×x=numx \times x = \textit{num} 的正整数 xx。在遍历中,如果出现正整数 xx 使 x×x>numx \times x > \textit{num},那么更大的正整数也不可能满足 x×x=numx \times x = \textit{num},不需要继续遍历了。

代码

class Solution {
    func isPerfectSquare(_ num: Int) -> Bool {
        var x: Int = 1
        var square: Int = 1
        while square <= num {
            if square == num {
                return true
            }
            x += 1
            square = x * x
        }
        return false
    }
}

复杂度分析

  • 时间复杂度:O(n)O(n),其中 nn 为正整数 num\textit{num} 的最大值。我们最多需要遍历 n+1\sqrt{n} + 1 个正整数。

  • 空间复杂度:O(1)O(1)

方法三:二分查找

思路及解法

考虑使用二分查找来优化方法二中的搜索过程。因为 num\textit{num} 是正整数,所以若正整数 xx 满足 x×x=numx \times x = \textit{num},则 xx 一定满足 1xnum1 \le x \le \textit{num}。于是我们可以将 1 和 num\textit{num} 作为二分查找搜索区间的初始边界。

细节

因为我们在移动左侧边界 left\textit{left} 和右侧边界 right\textit{right} 时,新的搜索区间都不会包含被检查的下标 mid\textit{mid},所以搜索区间的边界始终是我们没有检查过的。因此,当 left=right\textit{left} = \textit{right} 时,我们仍需要检查 mid=(left+right)/2\textit{mid} = (\textit{left}+\textit{right}) / 2

代码

class Solution {
    func isPerfectSquare(_ num: Int) -> Bool {
        var left: Int = 0
        var right: Int = num
        while left <= right {
            let mid = (right - left) / 2 + left
            let square = mid * mid
            if square < num {
                left = mid + 1
            } else if square > num {
                right = mid - 1
            } else {
                return true
            }
        }
        return false
    }
}

复杂度分析

  • 时间复杂度:O(logn)O(\log n),其中 nn 为正整数 num\textit{num} 的最大值。

  • 空间复杂度:O(1)O(1)