算法面试题2 统计元素个数

192 阅读3分钟

如下

image.png

这道题是leetCode中初级算法中的一题,算法面试中还是比较常见的,要求统计数字n以内的素数个数涉及到这种统计类的题,大多没有接触过算法的人可能第一想到的就是暴力统计

一.暴力统计

整理一下思路: 判断一个数是不是素数,就是判断除了1 和它本身之外还能不能被其他数整除,也就是说,当前数为 i,i 如果能被 2~(i-1) 之间的任何一个数整除,就代表这个数不是素数,仔细理解下,开始编码

public class ArithmeticTest {
    /**
     * 统计数字n以内的素数个数
     * 素数:只能被1 和本身整除的自然数 0和1 除外
     * 例 输入 100  输出 25
     */
    public static void main(String[] args) {

        long start = System.currentTimeMillis();
        // 为了性能对比 统计100000以内的
        int count = violenceStatistical(100000);

        System.out.println("共有素数个数:" + count);
        long end = System.currentTimeMillis();

        System.out.println("耗费时间:" + (end - start));

    }

    //暴力算法
    private static int violenceStatistical(int n) {
        //计数器
        int count =0;
        //遍历n 从2开始  0和1 直接排除
        for(int i=2;i<n;i++){
            //判断 i是素数 count+1,非素数 count+0
            count+=isPrime(i)?1:0;
        }
        return count;
    }
    private static boolean isPrime(int i) {
        //x 取值范围  2~(i-1)
        for(int x=2;x<i;x++){
            //判断 如果 x能被i整除,代表不是素数
            if(i%x==0){
                return false;
            }
        }
        return true;
    }

}

打印结果如下,花费了 6768ms

image.png

二.埃筛法

整理思路:首先将2到n范围内的整数写下来,其中2是最小的素数。将表中所有的2的倍数划去,表中剩下的最小的数字就是3,他不能被更小的数整除,所以3是素数。再将表中所有的3的倍数划去……以此类推,如果表中剩余的最小的数是m,那么m就是素数。然后将表中所有m的倍数划去,像这样反复操作,就能依次枚举n以内的素数,仔细理解下,编码如下

public class ArithmeticTest {
    /**
     * 统计数字n以内的素数个数
     * 素数:只能被1 和本身整除的自然数 0和1 除外
     * 例 输入 100  输出 25
     */
    public static void main(String[] args) {

        long start = System.currentTimeMillis();
        // 为了性能对比 统计100000以内的
        int count = eratosthenesStatistical(100000);

        System.out.println("共有素数个数:" + count);
        long end = System.currentTimeMillis();

        System.out.println("耗费时间:" + (end - start));

    }
    //埃筛法
    private static int eratosthenesStatistical(int n) {
        //声明一个长度为n的数组,布尔默认值是false,全是素数
        boolean[] isPrime=new boolean[n];
        //计数器
        int count =0;
        //遍历 从2开始  0和1 直接排除
        for(int i=2;i<n;i++){
            //如果为true就跳过
            if(!isPrime[i]){
                count++;
                //系数倍增,比如2 ,将数组中2的倍数都设置为true
                for(int j=2 *i;j<n;j+=i){
                    isPrime[j]=true;
                }
            }
        }
        return count;
    }

    //暴力算法
    private static int violenceStatistical(int n) {
        //计数器
        int count =0;
        //遍历n 从2开始  0和1 直接排除
        for(int i=2;i<n;i++){
            //判断 i是素数 count+1,非素数 count+0
            count+=isPrime(i)?1:0;
        }
        return count;
    }
    private static boolean isPrime(int i) {
        //x 取值范围  2~(i-1)
        for(int x=2;x<i;x++){
            //判断 如果 x能被i整除,代表不是素数
            if(i%x==0){
                return false;
            }
        }
        return true;
    }

}

看下打印结果 17ms!

image.png