题目类型: 素数个数统计
题目要求: 统计n以内的素数个数
public class PrimeNumber1 {
public static void main(String[] args) {
//打印100以内的素数个数(预计结果为25)
System.out.println("暴力算法统计素数个数为"+bf(100));
//测试结果确实为25
}
/**
* 使用暴力算法统计素数个数
* @param n 统计素数边界值
* @return 返回int型的素数个数
*/
public static int bf(int n) {
//统计素数个数的计数器
int count = 0;
//外层for循环遍历(其时间复杂度为n)
for (int i = 2; i < n; i++) {
//使用三元运算符: 判断数字i是否为素数, 若是素数(值为false), count值加1, 否则保持不变
// count += isPrime(i) ? 1 : 0;
//算法改进后进行素数判断
count += isPrime2(i) ? 1 : 0;
}
return count;
}
/**
* 判断当前数字是否为素数 原版
* @param x 整型自然数
* @return 布尔型值true或者false
*/
private static boolean isPrime(int x) {
//内层for循环遍历(其时间复杂度为x)
for (int i = 2; i < x; i++) {
//判断x是否为素数(即判断x是否能够被i整除)
if(x % i == 0) {
//若能被整除, 则返回false
return false;
}
}
//若不能被整除, 则返回true
return true;
}
/**
* 判断当前数字是否为素数 改进版
* 在第一版基础上降低算法时间复杂度
* @param x 整型数字
* @return 布尔型值true或者false
*/
private static boolean isPrime2(int x) {
/**
* 问题: 使用暴力算法时, 总的时间复杂度为n+x, 执行效率太低
* 改进思路:
* i的取值范围其实没必要取到x, 实际上只需要取到根号下x即可;
*
* 为什么取到根号下x就可以了呢?
* 假设x值为12, 那么12能被整除的组合因子有哪些呢?
* 包括: 1*12 2*6 3*4 4*3 6*2 12*1
* 我们发现, 前面三个跟后面三个的关系只是两个因子位置颠倒,
* 也就是满足乘法交换律, 只要能被前三个组合中的两个因子整除,
* 也一定能被后三个组合中的两个因子整除, 因此取到根号下x即可;
* 这样不仅可以减少for循环次数, 而且时间复杂度也随之降低
*/
//内层for循环遍历
// for (int i = 2; i < x; i++) {
//方式一: 使用Math.sqrt()函数开根号
for (int i = 2; i <= Math.sqrt(x); i++) {
//方式二: 使用i * i < x表示(作用相当于x开根号)
// for (int i = 2; i * i <= x; i++) {
//判断x是否为素数(即判断x是否能够被i整除)
if(x % i == 0) {
//若能被整除, 则返回false
return false;
}
}
//若不能被整除, 则返回true
return true;
}
}