返回

算法题解 LeetCode 204 统计所有小于非负整数 n 的质数数量

闲谈

题目概述

LeetCode 第 204 题,题目如下:

给定一个非负整数 n,请统计一下从 0 到 n-1 中有多少个质数。

示例 1:

输入:n = 10
输出:4
解释:小于 10 的质数有 2、3、5、7,一共有 4 个。

示例 2:

输入:n = 0
输出:0

示例 3:

输入:n = 1
输出:0

解题思路

暴力枚举

暴力枚举,按题意从 0 到 n-1 依次遍历每个数字,并判断每个数字是否为质数。如果一个数字是质数,计数器加 1。最后返回计数器。

判断一个数字是否为质数,可以采用以下步骤:

  1. 从 2 开始,依次尝试将数字除以从 2 到数字的平方根(包括平方根)之间的所有整数。
  2. 如果能被除尽,则数字不是质数;否则,数字是质数。
def count_primes(n):
  """
  统计小于非负整数 n 的质数的数量。

  Args:
    n: 非负整数。

  Returns:
    小于 n 的质数的数量。
  """

  # 特殊情况
  if n <= 1:
    return 0

  # 初始化计数器
  count = 0

  # 从 2 开始遍历
  for i in range(2, n):
    # 逐个数字判断是否是质数
    is_prime = True
    for j in range(2, int(i ** 0.5) + 1):
      if i % j == 0:
        is_prime = False
        break

    # 如果是质数,计数器加 1
    if is_prime:
      count += 1

  return count

埃拉托斯特尼筛法

埃拉托斯特尼筛法是一种更有效的方法来统计小于 n 的质数的数量。它通过筛选出所有小于 n 的非质数来实现。

具体的步骤如下:

  1. 将一个列表初始化为 True,列表的长度为 n。
  2. 从 2 开始,将列表中所有数字的倍数(除了数字本身)标记为 False。
  3. 遍历列表,并将所有仍然标记为 True 的数字计数。
def count_primes(n):
  """
  统计小于非负整数 n 的质数的数量。

  Args:
    n: 非负整数。

  Returns:
    小于 n 的质数的数量。
  """

  # 特殊情况
  if n <= 1:
    return 0

  # 初始化列表
  is_prime = [True] * n

  # 从 2 开始筛除非质数
  for i in range(2, int(n ** 0.5) + 1):
    if is_prime[i]:
      for j in range(i * i, n, i):
        is_prime[j] = False

  # 计数质数
  count = 0
  for i in range(2, n):
    if is_prime[i]:
      count += 1

  return count

复杂度分析

时间复杂度

暴力枚举的时间复杂度为 O(n log n),其中 n 为给定的整数。这是因为对于每个数字,都需要判断它是否为质数,这需要 O(log n) 的时间。

埃拉托斯特尼筛法的时间复杂度为 O(n log log n)。这是因为埃拉托斯特尼筛法只遍历了小于 n 的平方根的所有数字。

空间复杂度

暴力枚举的空间复杂度为 O(1),因为不需要额外的空间。

埃拉托斯特尼筛法的时间复杂度为 O(n),因为需要一个列表来存储是否为质数的信息。

总结

LeetCode 第 204 题,统计所有小于非负整数 n 的质数的数量。通过暴力枚举和埃拉托斯特尼筛法两种方法,可以解决该问题。暴力枚举的时间复杂度为 O(n log n),埃拉托斯特尼筛法的时间复杂度为 O(n log log n)。