转载请注明出处:http://blog.csdn.net/xiaojimanman/article/details/20062179
详细题目网址参照: http://hero.csdn.net/Question/Details?ID=287&ExamID=282
对于该问题的实现方式如下:
/**
*@Description: 半质数求法
*/
package cn.lulei.util;
import java.util.ArrayList;
import java.util.HashSet;
public class Test {
/**
* @param n
* @return
* @Date: 2014-2-27
* @Author: lulei
* @Description: 判断一个整数是不是质数
*/
public static boolean isPrimeNumber(int n){
int i;
for (i = 2; i <= n; i++){
if (0 == (n % i))
break;
}
return i == n;
}
/**
* @param start
* @param end
* @return
* @Date:2014-2-27
* @Author:lulei
* @Description: 求 start 到 end 之间的半质数的个数
*/
public static int get2PrimeNumberCount(int start, int end) {
int sum = 0;
//保存2到end之间的所有素数
ArrayList<Integer> array = new ArrayList<Integer>();
//计算2到end之间的所有素数
for (int i = 2; i <= end; i++){
if (isPrimeNumber(i)) {
array.add(i);
}
}
for (int i = start; i <= end; i++){
for(int j = 0; j < array.size() && array.get(j) < i; j++) {
int k = i / array.get(j);
if ((k * array.get(j) == i) && array.contains(k)){
sum++;
break;
}
}
}
return sum;
}
/**
* @param start
* @param end
* @return
* @Date:2014-2-27
* @Author:lulei
* @Description: 求 start 到 end 之间的半质数的个数
*/
public static int get2PrimeNumberCount2(int start, int end) {
//保存2到end之间的所有素数
ArrayList<Integer> array = new ArrayList<Integer>();
//计算2到end之间的所有素数
for (int i = 2; i <= end; i++){
if (isPrimeNumber(i)) {
array.add(i);
}
}
HashSet<Integer> numArray = new HashSet<Integer>();
for (int i = 0; i < array.size(); i++){
for(int j = i; j < array.size(); j++) {
int num = array.get(i) * array.get(j);
if (num < start) {
continue;
} else if (num > end) {
break;
} else {
numArray.add(num);
}
}
}
return numArray.size();
}
/**
* @param n
* @return
* @Date:2014-2-27
* @Author:lulei
* @Description: 判断一个数是否是半质数
*/
public static boolean is2PrimeNumber(int n) {
int count = (int) Math.sqrt(n);
for (int i = 2; i <= count; i++) {
if (isPrimeNumber(i)){
int j = n / i;
if ((i * j == n) && isPrimeNumber(j)){
return true;
}
}
}
return false;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
long a = System.currentTimeMillis();
System.out.println(Test.get2PrimeNumberCount2(2, 10000));
long b = System.currentTimeMillis();
System.out.println(b - a);
long a1 = System.currentTimeMillis();
System.out.println(Test.get2PrimeNumberCount(2, 10000));
long b1 = System.currentTimeMillis();
System.out.println(b1 - a1);
}
}
该实现方法中,使用了get2PrimeNumberCount 和get2PrimeNumberCount2 两种实现方式,自己通过简单的测试 get2PrimeNumberCount2 的效率 高于 get2PrimeNumberCount 。
对于该问题的实现方式,都是先求出[2, end]之间的所有素数,通过循环这些质数去验证或者去求半质数,个人认为这种方式的效率要高于循环验证i时候是半质数。
下面给出一个方法验证一个数是否是半质数
/**
* @param n
* @return
* @Date:2014-2-27
* @Author:lulei
* @Description: 判断一个数是否是半质数
*/
public static boolean is2PrimeNumber(int n) {
int count = (int) Math.sqrt(n);
for (int i = 2; i <= count; i++) {
if (isPrimeNumber(i)){
int j = n / i;
if ((i * j == n) && isPrimeNumber(j)){
return true;
}
}
}
return false;
}
上述求N之内的所有素数效率太低,下面给出一个比较高效的方法。
/**
* @param start
* @param end
* @return
* @Date:2014-2-28
* @Author:lulei
* @Description: 求 end 之内的素数
*/
public static ArrayList<Integer> getPrimeArray(int end) {
ArrayList<Integer> array = new ArrayList<Integer>();
boolean[] flag = new boolean[end + 1];
Arrays.fill(flag, false);
for (int i = 2; i <=end; i++){
if (!flag[i]) {
array.add(i);
}
for (int j = 0; j < array.size() && (i * array.get(j) <= end); j++){
flag[i * array.get(j)] = true;
if (i % array.get(j) == 0) {
break;
}
}
}
return array;
}
将上述方法体内求end之内的素数换成调用该方法即可。效率提升到求200W以内的半质数耗时500ms
最后给出最终的java代码实现:
/**
*@Description: 半质数求法
*/
package cn.lulei.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
public class Test {
/**
* @param n
* @return
* @Date: 2014-2-27
* @Author: lulei
* @Description: 判断一个整数是不是质数
*/
public static boolean isPrimeNumber(int n){
int i;
for (i = 2; i <= n; i++){
if (0 == (n % i))
break;
}
return i == n;
}
/**
* @param start
* @param end
* @return
* @Date:2014-2-27
* @Author:lulei
* @Description: 求 start 到 end 之间的半质数的个数
*/
public static int get2PrimeNumberCount(int start, int end) {
//保存2到end之间的所有素数
ArrayList<Integer> array = getPrimeArray(end);
HashSet<Integer> numArray = new HashSet<Integer>();
for (int i = 0; i < array.size(); i++){
for(int j = i; j < array.size(); j++) {
int num = array.get(i) * array.get(j);
if (num < start) {
continue;
} else if (num > end) {
break;
} else {
numArray.add(num);
}
}
}
return numArray.size();
}
/**
* @param n
* @return
* @Date:2014-2-27
* @Author:lulei
* @Description: 判断一个数是否是半质数
*/
public static boolean is2PrimeNumber(int n) {
int count = (int) Math.sqrt(n);
for (int i = 2; i <= count; i++) {
if (isPrimeNumber(i)){
int j = n / i;
if ((i * j == n) && isPrimeNumber(j)){
return true;
}
}
}
return false;
}
/**
* @param start
* @param end
* @return
* @Date:2014-2-28
* @Author:lulei
* @Description: 求 end 之内的素数
*/
public static ArrayList<Integer> getPrimeArray(int end) {
ArrayList<Integer> array = new ArrayList<Integer>();
boolean[] flag = new boolean[end + 1];
Arrays.fill(flag, false);
for (int i = 2; i <=end; i++){
if (!flag[i]) {
array.add(i);
}
for (int j = 0; j < array.size() && (i * array.get(j) <= end); j++){
flag[i * array.get(j)] = true;
if (i % array.get(j) == 0) {
break;
}
}
}
return array;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
long a = System.currentTimeMillis();
System.out.println(Test.get2PrimeNumberCount(2, 2000000));
long b = System.currentTimeMillis();
System.out.println(b - a);
}
}
如果在上述代码第47行对add的次数进行计数,200W得到的结果是 add次数46548,hashSet的大小是46111,中间有一定的误差,但是一个合数的分解质因数的结果是唯一的,这中间存在一定的矛盾,自己也通过一些简单的测试,发现hashSet会将两个不同的int值存在一个位置上,这一点还有待继续验证。