Bootstrap

Leetcode打卡:统计不是特殊数字的数字数量

执行结果:通过

题目:3233 统计不是特殊数字的数字数量

给你两个 正整数 l 和 r。对于任何数字 xx 的所有正因数(除了 x 本身)被称为 x 的 真因数

如果一个数字恰好仅有两个 真因数,则称该数字为 特殊数字。例如:

  • 数字 4 是 特殊数字,因为它的真因数为 1 和 2。
  • 数字 6 不是 特殊数字,因为它的真因数为 1、2 和 3。

返回区间 [l, r] 内 不是 特殊数字 的数字数量。

示例 1:

输入: l = 5, r = 7

输出: 3

解释:

区间 [5, 7] 内不存在特殊数字。

示例 2:

输入: l = 4, r = 16

输出: 11

解释:

区间 [4, 16] 内的特殊数字为 4 和 9。

提示:

  • 1 <= l <= r <= 109

代码以及解题思路

代码:

MX = 10 ** 5 + 1
is_primes = [True] * MX
primes = []
for i in range(2,MX):
    if not is_primes[i]: continue
    primes.append(i * i)
    for j in range(i * i,MX,i):
        is_primes[j] = False

class Solution:
    def nonSpecialCount(self, l: int, r: int) -> int:
        L = bisect_left(primes,l)
        R = bisect_right(primes,r)
        return (r - l + 1) - (R - L)

解题思路:

  1. 初始化数组和变量
    • MX = 10 ** 5 + 1:定义一个上限 MX,因为我们想要处理的是小于或等于 105 的所有数。
    • is_primes = [True] * MX:创建一个布尔数组 is_primes,初始时所有数都被假定为素数(即 True)。
    • primes = []:创建一个空列表 primes,用于存储实际找到的素数。
  2. 素数筛法(Sieve of Eratosthenes)
    • 遍历从 2 到 MX-1 的每个数 i
    • 如果 is_primes[i] 为 True(即 i 是素数),则执行以下操作:
      • 将 i * i 添加到 primes 列表中,因为我们需要记录每个素数的平方。
      • 从 i * i 开始,以 i 为步长,将 is_primes 数组中对应的值设置为 False,因为它们是 i 的倍数,即合数。
    • 注意:我们只处理素数的平方和它们的倍数,因为我们只对判断数是否为某个素数的平方的倍数感兴趣。
  3. 定义 Solution 类和 nonSpecialCount 方法
    • 在 Solution 类中,定义方法 nonSpecialCount(self, l: int, r: int) -> int
    • 使用 bisect_left 和 bisect_right 函数(这里假设已经从 bisect_module 导入了 bisect_left 和 bisect_right)来快速定位区间 [l, r] 在 primes 列表中的位置。
      • L = bisect_left(primes, l):找到 primes 中第一个不小于 l 的数的索引。
      • R = bisect_right(primes, r):找到 primes 中第一个大于 r 的数的索引。
    • 计算区间 [l, r] 内非特殊数的个数:
      • 首先,整个区间 [l, r] 内有 r - l + 1 个数。
      • 然后,从 primes 列表中,L 到 R-1 索引对应的素数平方会覆盖一部分区间 [l, r] 内的数,使它们成为特殊数。
      • 因此,非特殊数的个数为总个数减去特殊数的个数,即 (r - l + 1) - (R - L)
;