求一个数的素数对个数(枚举、筛素数法)
2018-03-24 14:51
183 查看
题目:给定一个数n,求它可以是多少对不同的素数对相加之和。
思路1:直接枚举,找出从2到n/2的素数,然后判断n与该素数的差是否为素数。实现非常简单,代码如下:
import java.util.Scanner;
public class Main {
public static void main(String []args) {
Scanner in = new Scanner(System.in);
int count = 0,t = 0;
int n = in.nextInt();
for(int i=2;i<=n/2;i++) {
if(is_prime(i)) {
t = n-i;
if(is_prime(t))
count++;
}
}
System.out.println(count);
}
public static boolean is_prime(int a) {
int i = (int) Math.sqrt(a);
int j = 2;
for(;j<=i&&a%j!=0;j++);
return j>i;
}
}
但此方法的时间复杂度高达O(n^2),如图所示:
n非常大的时候耗时几乎无法忍受,这时我们应该换一种思路。
第二种思路就筛素数法,它可以在O(n)的时间内求出一个区间内的所有素数,然后只要依个枚举判断即可在非常短的时间内求出结果。
首先我们先根据输入数n创建一个n+1大小的数组,之后再筛选出该区间的素数:
public static void prime_table(int arr[]) {
int max = arr.length-1;
arr[0] = arr[1] = 1;
for(int i=2;i<=max/2;i++)
for(int j=2;j<=i&&j*i<=max;j++)
if(arr[j]!=1) {
arr[j*i] = 1;//将一个合数重置为1表示它不是一个素数
if(i%arr[j]==0)
break;
}
}
筛素数法是根据每一个合数都能拆分成一个素数与任意数之积实现的,此外我们还要注意避免重复计算,使每个合数都只被其最小的素因子筛出。
筛出一个该区间的素数之后只需要顺序遍历素数表即可:
public static int prime_double(int arr[],int n) {
if(n<4)
return 0;
int count = 0;
for(int i=2;i<n/2;i++)
if(arr[i]!=1&&arr[n-i]!=1)//如果i是一个素数,查看一下n-i是不是素数即可。
count++;
return count;
}
该算法的耗时基本只花在创建素数表上:
但需要注意的是筛素数法的空间复杂度也高达O(n),如果n过大的话则会导致内存溢出。
一个int类型占4个字节,我这台电脑上的虚拟机堆的默认大小好像只有1.5G那样子,n>350000000就会导致堆溢出,大家可以手动设置一下堆的大小。
如果你有更好的思路欢迎在评论区分享交流,感谢观看。
思路1:直接枚举,找出从2到n/2的素数,然后判断n与该素数的差是否为素数。实现非常简单,代码如下:
import java.util.Scanner;
public class Main {
public static void main(String []args) {
Scanner in = new Scanner(System.in);
int count = 0,t = 0;
int n = in.nextInt();
for(int i=2;i<=n/2;i++) {
if(is_prime(i)) {
t = n-i;
if(is_prime(t))
count++;
}
}
System.out.println(count);
}
public static boolean is_prime(int a) {
int i = (int) Math.sqrt(a);
int j = 2;
for(;j<=i&&a%j!=0;j++);
return j>i;
}
}
但此方法的时间复杂度高达O(n^2),如图所示:
n非常大的时候耗时几乎无法忍受,这时我们应该换一种思路。
第二种思路就筛素数法,它可以在O(n)的时间内求出一个区间内的所有素数,然后只要依个枚举判断即可在非常短的时间内求出结果。
首先我们先根据输入数n创建一个n+1大小的数组,之后再筛选出该区间的素数:
public static void prime_table(int arr[]) {
int max = arr.length-1;
arr[0] = arr[1] = 1;
for(int i=2;i<=max/2;i++)
for(int j=2;j<=i&&j*i<=max;j++)
if(arr[j]!=1) {
arr[j*i] = 1;//将一个合数重置为1表示它不是一个素数
if(i%arr[j]==0)
break;
}
}
筛素数法是根据每一个合数都能拆分成一个素数与任意数之积实现的,此外我们还要注意避免重复计算,使每个合数都只被其最小的素因子筛出。
筛出一个该区间的素数之后只需要顺序遍历素数表即可:
public static int prime_double(int arr[],int n) {
if(n<4)
return 0;
int count = 0;
for(int i=2;i<n/2;i++)
if(arr[i]!=1&&arr[n-i]!=1)//如果i是一个素数,查看一下n-i是不是素数即可。
count++;
return count;
}
该算法的耗时基本只花在创建素数表上:
但需要注意的是筛素数法的空间复杂度也高达O(n),如果n过大的话则会导致内存溢出。
一个int类型占4个字节,我这台电脑上的虚拟机堆的默认大小好像只有1.5G那样子,n>350000000就会导致堆溢出,大家可以手动设置一下堆的大小。
如果你有更好的思路欢迎在评论区分享交流,感谢观看。
相关文章推荐
- 通过一个函数,判断输入的数是不是素数
- 哥德巴赫猜想-一个偶数可以表示为两个素数之和
- 今天遇到一个定义一个枚举变量的问题。
- 如何简单判断一个数是否为素数?
- 求一个特定函数在定义区间上的值是否都为素数
- 异或运算,,,只是一个小数据的枚举
- 用友uap nc65 如何实现一个下拉框(枚举类型实体)
- 嘿牛程序员__成都传智博客__枚举的一个带参构造函数的实现——以交通灯的转换为例
- 腾讯2017校招编程:一个数等于两个素数的和
- 用Java声明一个方法(函数)找出输入数值的范围去全部素数(质数)
- 输入一个整数看它是不是素数
- 写一个函数,判断素数
- p是一个大于3的素数,证明:7^p-6^p-1是43的倍数
- 判断一个数是不是素数
- 第十一周项目6 (4)输入一个数,输出这个数以内的所有回文素数
- c语言判断素数和输入一个数n代表有n行数据的问题
- 一个枚举的DropDowList
- 一个筛选法求素数的函数
- 判断一个数是否是素数
- 一个进行枚举选择的jquery插件(仿easyui风格)