欧拉筛

以前只会j += i的那种筛法,因为有重复,所以效率不是太高。而欧拉筛可以在O(n)的时间内筛出素数来,就要好用一点了。

其原理就是每个合数都可以表示为几个素数乘积的形式,这些素数当中就有一个最小的。如果每个合数都只由它们的最小的素因子来筛出来的话,就避免了重复。

for(int i = 2; i <= 10000; ++ i)
{
    if(!prime[i])
    {
        prime[++ prime[0]] = i;
    }
    for(int j = 1; j <= prime[0] && prime[j] * i < 10000; ++ j)
    {
        prime[prime[j] * i] = 1;
	if(i % prime[j] == 0)
	{
		break;
	}
    }
}

前面都还好,比较费点力理解的就是if(i % prime[j] == 0)就break这里不太好理解。

看其他大佬的解释就是假如i % prime[j] == 0,那么就可以设prime[j] * k == i,那么如果不break的话,就会继续筛i * prime[j + 1],但是i * prime[j + 1]就等于prime[j] * k * prime[j + 1],而prime[j + 1]是大于prime[j]的,所以当i == k * prime[j + 1]时,就会把它筛掉,所以就不用用prime[j + 1]来筛掉它了.

这样就避免了重复,保证了每个合数都只由它最小的素因子来筛掉它,让时间复杂度在O(n)上。

<think>好的,我现在需要回答用户关于如何用Python实现欧拉筛法的问题。首先,用户提到了参考资料的引用,特别是引用[4],里面提到了质数筛法的几种方法,包括欧拉筛法。我需要仔细看看引用[4]中的代码,但看起来可能是个常规筛法或埃氏,因为欧拉通常更高效,但需要不同的实现方式。 用户的问题明确指向欧拉筛法,所以我需要确保提供的代码是真正的欧拉,而不是埃氏或其他。首先,我应该回顾欧拉筛法的原理。欧拉筛法,也称为线性筛法,其核心思想是每个合数只被其最小的质因数掉,这样每个数只被一次,时间复杂度是线性的O(n)。 接下来,我需要检查引用[4]中的代码是否真的实现了欧拉。根据提供的代码: from math import sqrt def hanshu(n): ls,x,y=[True]*(n+1),2,int(sqrt(n))+1 while x<y: if ls[x]==True: for i in range(x*2,n+1,x): ls[i]=False x+=1 ls=[i for i in range(2,n+1) if ls[i]==True] return ls print(hanshu(100)) 这段代码看起来像是埃氏筛法,因为外层循环是遍历到sqrt(n),而内层循环从x*2开始,步长为x。埃氏筛法的时间复杂度是O(n log log n),而欧拉是线性的。因此,引用[4]中的代码可能不是欧拉的正确实现,用户可能需要正确的欧拉代码。 因此,我需要提供正确的Python实现欧拉筛法的代码。正确的欧拉通常会维护一个质数列表,并遍历每个数,用已知的质数去标记合数,并且在发现当前数是某个质数的倍数时提前终止循环,以确保每个合数只被标记一次。 例如,正确的欧拉代码结构大致如下: def euler_sieve(n): is_prime = [True] * (n + 1) primes = [] for i in range(2, n + 1): if is_prime[i]: primes.append(i) for p in primes: if i * p > n: break is_prime[i * p] = False if i % p == 0: break return primes 我需要验证这段代码是否正确。在欧拉中,对于每个数i,如果是质数,就加入质数列表。然后对于每个已找到的质数p,标记i*p为合数。关键点在于当i能被p整除时,停止进一步的标记,这样确保每个合数只被最小的质因数掉。 例如,当i=4时,质数列表是[2,3]。首先处理p=2,标记4*2=8为合数,然后因为4%2==0,所以break,不处理p=3。这样,当i=6时,处理到p=2时标记12,然后因为6%2==0,break,避免了后续用更大的质数去标记已经被过的数。 因此,这段代码是正确的欧拉实现。接下来,我需要将这段代码整合到回答中,并解释其步骤,确保用户理解。 另外,用户可能还需要了解欧拉筛法的优势,比如时间复杂度为O(n),比埃氏更高效,特别是处理大数时。同时,需要注意正确实现的关键点,如及时break以避免重复标记。 最后,根据用户的要求,生成相关问题,比如与其他筛法的比较,优化方法,应用场景等。</think>### Python实现欧拉筛法 欧拉筛法(线性筛法)用于高效生成质数列表,其核心思想是**每个合数仅被其最小质因数除**,时间复杂度为$O(n)$。以下是实现步骤及代码: **实现步骤** 1. 初始化一个布尔数组`is_prime`标记是否为质数 2. 维护质数列表`primes`用于存储已确认的质数 3. 遍历每个数$i$,若未被标记为合数则加入质数列表 4. 用当前数$i$与已知质数$p$相乘生成合数$i \times p$并标记,当$i$能被$p$整除时终止内层循环 **Python代码实现** ```python def euler_sieve(n): is_prime = [True] * (n + 1) # 初始标记所有数为质数 primes = [] # 存储质数结果 for i in range(2, n + 1): if is_prime[i]: primes.append(i) # 当前数是质数,加入列表 # 用已知质数标记合数 for p in primes: composite = i * p if composite > n: # 超过范围则终止 break is_prime[composite] = False if i % p == 0: # 关键:确保每个合数仅被最小质因数除 break return primes # 示例:选100以内的质数 print(euler_sieve(100)) # 输出:[2, 3, 5, ..., 97] ``` **关键点说明** - **线性时间复杂度**:每个合数只被标记一次,效率高于埃氏筛法的$O(n \log \log n)$[^4] - **终止条件`i % p == 0`**:保证合数$i \times p$仅被其最小质因数$p$除。例如当$i=4$时,$p=2$标记8后终止,避免后续用$p=3$标记12(此时12应由$i=6$与$p=2$标记)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值