英雄会半质数的个数实现

转载请注明出处: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值存在一个位置上,这一点还有待继续验证。

你可能感兴趣的:(java,实现,英雄会,半个质数)