版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
求素数的个数。本题要求编写一个程序,求1~n的素数个数。 要求至少给出两种解法,对于相同的n,给出这两种解法的结果,通过相关数据进行测试,目的是通过对比同一问题不同解法的绝对执行时间体会如何设计“好”的算法。
时间限制: 200 ms
内存限制: 64 MB
代码长度限制: 16 KB
输入格式:
输入在一行中给出1个整数n(<= 10 000 000)。
输出格式:
对每一组输入,在一行中输出1~n的素数个数。
输入样例1:
5
输出样例1:
3
输入样例2:
14
输出样例2:
6
第一种方法:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int sum = 1;
if(n==1)
System.out.println("0");
else if(n==2)
System.out.println("1");
else {
for(int i=3;i<=n;i++) {
int j=2;
int size=(int)Math.sqrt(i);
for(;j<size;j++) {
if(i%j==0)
break;
}
if(j==size) {
sum++;
}
}
System.out.println(sum);
}
}
}
第二种方法(埃氏筛法):
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] num = new int[n+1];
int sum = 0;
for(int i=2;i<=n;i++) {
if(num[i]==0) {
sum++;
int j=i+i;
while(j<=n) {
num[j]=1;
j+=i;
}
}
}
System.out.println(sum);
}
}
最终改进后:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] num = new int[n+1];
int sum = 1;
if(n<=1)
System.out.println(0);
else if(n==2)
System.out.println(1);
else {
for(int i=3;i<=n;i+=2) {
if(num[i]==0) {
sum++;
int tmp = i+i; //存值 i+i,减少运算次数,相当于跳过了偶数次的运算,因为偶数除了2不会再有素数
int j=tmp+i; //相当于3个i相加
while(j<=n) {
num[j]=1;
j+=tmp;
}
}
}
System.out.println(sum);
}
}
}
这个题让我真的从时间上感受到了代码的“好坏”,这应该还不是最简的方法,因为我依然没有拿到全分,还是有一个测试点运行超时了,200ms的运行时间确实很考验人。第一种方法就是最基本的方法,一般初学者刚开始学用的最多的方法;第二种我建立了一个数组,因为1不算,从2开始进行判断,素数自身的倍数是合数,我的思路是把n个数遍历一遍,在遍历前面的数时直接把明确是合数的标记出来,则在遍历的过程中未标记的就是素数,虽然没能拿到全分,但这种方式相较于第一种在时间上还是有一个提升;第三种方法是第二种方法的改进,因为除2以外的偶数都是合数,所以直接不再去考虑偶数,相当于减少了一半的计算量,但结果还是超时了,实在没办法了。至于最终能拿全分的正解,等我克服掉以后再回来补充。。。如果有了解这个题正解的,麻烦告诉我怎么做,我实在是懵了。