小唐龙的质数筛:

质数筛:

质数定义:

若一个正整数无法被除了 1 和它自身之外的任何自然数整除,则称该数为质数(或者素数),否则称该自然数为合数。

题目链接:

204. 计数质数

image-20240421163946257

int countPrimes(int n){
    int sum = 0;
    while(n--){
        
        if(isPrime(n))sum++;
    }
    return sum;
}

题目逻辑很简单,主要是判断素数。下面我们来看isPrime函数的编写。

1.暴力解法:

bool isPrime(int n){
	if(n<2){
		return false;
	}
	for(int i = 2; i < sqrt(n); i++){
		if(n % i == 0){
			return false;
		}
	}
	return true;
}

时间复杂度:emm O(n),算上外面那层while就是O(n^2),很明显过不去,超时了。

image-20240421164636654

那么接下来先优化一下吧。我们知道,一个数是不是质数得由两个数的乘积能否得到它来判断,所以,我们可以发现,i < n 这个判断条件,完全可以用i <= √n 来替换,因为到了后面其实是进行了重复的判断。

那么就可以优化为:

bool isPrime(int n){
	if(n<2){
		return false;
	}
	for(int i = 2; i <= sqrt(n); i++){
		if(n % i == 0){
			return false;
		}
	}
	return true;
}

时间复杂度:O(n * √n )。

过了吗,当然没过,这次卡在了第21个测试点,起码说明我们的优化是有效果的,那就继续进行。

首先在自然数中,2和3是很常见的约数,我们是不是可以将其去处呢,当然可以。对于一个数对6取余,如果其模1或5,那么自然就不是2和3的公倍数。

int isPrime(int n){
    if(n==2||n==3|n==5)return 1;
    if(n==1||n==4||n==0)return 0;
    if(n%6==1||n%6==5){
        for(int i = 2 ; i <= sqrt(n) ; i++){
            if(n%i==0)return 0;
        }return 1;
    }
    return 0;
}

当然,还是过不了。emm,说明在数据量很大的情况下,只是单纯的优化判断每个数是不是质数是不行的,我们要减少对数的判断。比如一个很大的质数它的倍数,用上面的算法可能就得判断很多次。我们是不是可以避免这样的判断呢。接下来,请看质数筛。

埃氏筛:
int isPrime[5000000];//定义在全局变量的数组初始值为0,不用遍历赋值0。
int countPrimes(int n) {
    if (n < 2) {
        return 0;
    }
    int sum = 0;
    for (int i = 2; i < n; ++i) {
        if (isPrime[i] == 0) {
            sum += 1;
            if (i <= sqrt(n)) {
                for (int j = i * i; j < n; j += i) {
                    isPrime[j] = 1;
                }
            }
        }
    }
    return sum;
}

时间复杂度:O(nloglogn),证明比较麻烦,作者也就大概看懂,这里就不说出来了,(避免丢人)咳咳。

空间复杂度:O(n)。

最后,其实还有个更nb的线性筛时间复杂度和空间复杂度都为O(n)。这个我还得捋一捋,本质上还是在埃氏筛上进行了优化。等我学会了再进行补充。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值