执行结果:通过
题目:3233 统计不是特殊数字的数字数量
给你两个 正整数 l
和 r
。对于任何数字 x
,x
的所有正因数(除了 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)
解题思路:
- 初始化数组和变量:
MX = 10 ** 5 + 1
:定义一个上限MX
,因为我们想要处理的是小于或等于 105 的所有数。is_primes = [True] * MX
:创建一个布尔数组is_primes
,初始时所有数都被假定为素数(即True
)。primes = []
:创建一个空列表primes
,用于存储实际找到的素数。
- 素数筛法(Sieve of Eratosthenes):
- 遍历从 2 到
MX-1
的每个数i
。 - 如果
is_primes[i]
为True
(即i
是素数),则执行以下操作:- 将
i * i
添加到primes
列表中,因为我们需要记录每个素数的平方。 - 从
i * i
开始,以i
为步长,将is_primes
数组中对应的值设置为False
,因为它们是i
的倍数,即合数。
- 将
- 注意:我们只处理素数的平方和它们的倍数,因为我们只对判断数是否为某个素数的平方的倍数感兴趣。
- 遍历从 2 到
- 定义 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)
。
- 首先,整个区间
- 在