PAT 乙级 1013 数素数 Java解决

写在最前:欢迎批评,欢迎任意地方的指正,用你们的优秀的java代码砸死我吧!!

问题——————

令 P​i​​ 表示第 i 个素数。现任给两个正整数 M≤N≤10^​4​​,请输出 P​M​​ 到 P​N​​ 的所有素数。

输入格式:

输入在一行中给出 M 和 N,其间以空格分隔。

输出格式:

输出从 P​M​​ 到 P​N​​ 的所有素数,每 10 个数字占 1 行,其间以空格分隔,但行末不得有多余空格。

输入样例:

5 27

输出样例:

11 13 17 19 23 29 31 37 41 43
47 53 59 61 67 71 73 79 83 89
97 101 103

 解题思路:

题很简单,难得是写法,这个题要求求第一万个素数,咱一开始也不知道第一万个素数是多少(虽然写完以后知道了),咱也不敢问,咱只敢自己写一下。目前的思路就是求出来所有的素数,然后存到一个数组里,按要求输出就好了。趁这个机会整理一下素数的求法吧。

  • 简单遍历
    public static boolean isPrime(int a) {
    		for(int i = 2;i<=a;i++) {
    			//最简单的素数判断方法
    			if(a%i == 0) 
    				return false;
    		}
    		return true;
    	}

    最简单的从2开始到要求的数本身a,如果有任何一个数能整除a,直接退出循环,返回false,否则到最后返回true。这种方法一般是第一天学代码老师讲的求素数方法,简单易懂,但是效率极低,下面看优化后:

  • 优化遍历
    public static boolean isPrime(int a) {
    		for(int i = 2;i<=Math.sqrt(a);i++) {
    			//最简单的素数判断方法
    			//遍历从2到根号a的所有正整数,只要可以整除就返回false,没有的话最后返回true
    			if(a%i == 0) 
    				return false;
    		}
    		return true;
    	}

    这个是从2开始遍历到a的根号,原理也通俗易懂,只是需要注意,因为如果对a来说,开方以前的数如果没有数可以整除a,那么后面的数也不可能整除a,因为如果要整除他就必须乘以一个比a的开方小的数字,而这个数字在之前又已经检查过。举个栗子,对于36来说,从一到六都处理以后,比6大的数比如12,18都能整除36,但是这两个数分别乘以3和2才等于36,而3和2又检查过,所以不需要在一边检查12和18。这种方法的效率要高一些。 

  • 烂素数筛
    public static boolean[] Primes() {
    		long start  = System.currentTimeMillis();
    		boolean[] primes = new boolean[100000];
    		for(int i=2;i<100000;i++) {
    			if(primes[i] == false) {
    				for(int j=i+1;j<100000;j++) {
    					if(j%i == 0) {
    						primes[j]=true;
    					}
    				}
    			}
    		}
    		long end  = System.currentTimeMillis();
    		System.out.println(end-start);
    		return primes;
    	}

    先说一下素数筛的用法,素数筛一般是求大量素数的时候使用的一种方法,基本思路是对一个布尔类型数组做处理,下标代表数,数组值代表这个数是不是素数。一般都是true代表素数,但是数组建立初期是false,这个算法又是对非素数进行处理,为了省略对数组的整体赋值,这里就把false代表素数。然后遍历这个数组,每个元素进行判断,判断是否是素数(false),如果是素数,就把这个素数的所有倍数都赋值为true,表示这个素数的所有倍数都不是素数(一定),完整遍历即可。但是我个人对这个的理解比较粗糙,这道题起初用的是上面的写法,遍历的时候使用的是j++;也就是一个一个地检查,速度奇慢,计算十万以内的所有素数需要用一秒多,可以吧上面的方法自行复制运行。今天才看到的优化算法(我也不知道是不是人家本来就是这个样子..我理解出问题,对不起啊埃拉托斯特尼)优化:

  • 优化素数筛
    public static boolean[] Primes() {
    		long start  = System.currentTimeMillis();
    		boolean[] primes = new boolean[100000000];
    		for(int i=2;i<100000000;i++) {
    			if(primes[i] == false) {
    				for(int j=i+i;j<100000000;j+=i) {//注意这行
    					if(j%i == 0) {
    						primes[j]=true;
    					}
    				}
    			}
    		}
    		long end  = System.currentTimeMillis();
    		System.out.println(end-start);
    		return primes;
    	}

    这里对在后面遍历的时候的步长做出了优化,反正我检查的也是当前数(i)的倍数,所以直接把步长设置为i,就很快了。这个算一亿以内的素数大概只要一秒多点,1000万以内只要一百多毫秒,这题最多要到105000,大概也就十几毫秒得出这个数组,缺点就是会重复筛除,比如对于8和16,在2和4的时候都进行了计算,解决这个问题的欧拉筛法我没有太搞懂,先不贴了,这个筛法比较简单好写,效率也比较高,做题的时候可以使用。

有了素数以后这道题就没有什么能挡住你的了,按照要求把需要的数据放到Stringbuilder中,记得放换行,输出就好了

package not.die.in.here;

import java.util.Scanner;

public class _1013_CountingPrime {
	static boolean[] primes = Primes();//静态加快速度
	static boolean[] Primes() {
		boolean[] primes = new boolean[105000];
		for(int i=2;i<primes.length;i++) {
			if(primes[i] == false) {
				for(int j=i+i;j<primes.length;j+=i) {
					if(j%i == 0) {
						primes[j]=true;
					}
				}
			}
		}
		return primes;
	}
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);//只读两个数据不需要buff
		int a= sc.nextInt();
		int b = sc.nextInt();
        sc.close();
		int temp = 0;
		StringBuilder sb = new StringBuilder("");
		for(int i=1;i<primes.length;i++) {
			if(!primes[i]) {//判断每个数是不是素数,是就放入
				temp++;
				if(temp<=b+1 &&temp>a) {
					sb.append(i);
					if((temp-a)% 10 == 0) {
						sb.append("\n");//每十个放一个换行
					}else {
						sb.append(" ");//每一个放一个空格
					}
				}
				if(temp>b)
					break;
			}
		}
		System.out.println(sb.toString().trim());//去除多余空格输出
	}

}

提交截图:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值