转载请注明出处: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); } }
对于该问题的实现方式,都是先求出[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); } }