【LeetCode】 Count Primes 解题报告

Count Primes

[LeetCode]

https://leetcode.com/problems/count-primes/

Total Accepted: 36655 Total Submissions: 172606 Difficulty: Easy

Question

Count the number of prime numbers less than a non-negative number, n.

Examples

题目网址给的Hint帮了大忙

Ways

方法一

最简单的方法就是遍历的方法,直接判断小于n的所有数中质数数目,这就是方法一。

但是这个方法效率太低,提交的时候连续三次都超出时间限制了。本地运行还是可以的。迫于无奈,必须提高效率。

方法二

http://blog.csdn.net/blitzskies/article/details/45442923 提示用Sieve of Eratosthenes的方法。

也是学习了。

也根据LeetCode 给的提示信息,一步步做出来。图非常明白了,把所有数字的倍数都删除的方法。

重点是优化效率,每一步的效率都要优化。

用List都会效率低,最后用数组好了。

这个题竟然是Easy难度。。

/**
 * 统计质数的数目。使用数组,用列表效率低。
 *
 * @param n
 * @return
 */
public static int countPrimes3(int n) {

    //n个元素的数组,其实只用到了n-2个。多见了2个防止输入0的时候崩溃。
    int[] nums = new int[n];
    //把所有的小于n的大于2的数字加入数组里
    for (int i = 2; i < n; i++) {
        //注意计算质数从2开始的,而数组从0开始
        nums[i - 2] = i;
    }
    //统一的长度,优化计算
    int size = nums.length;
    //各种优化效率,只计算到sqrt(n)
    for (int i = 0; i * i < size; i++) {
        //获取数组中的数字
        int temp = nums[i];
        //如果不是0,则进行计算,否则直接跳过,因为这个数已经是之前的某数字的倍数
        if (temp != 0) {
            //把该数字的倍数都删去,因为他们都不是质数
            //int i1 = temp - 1  优化效率,是因为比如用5来删除数字的时候15=3*5已经被删除过了,所以从20=5*4开始删除
            for (int i1 = temp - 1; i + temp * i1 < size; i1++) {
                //如果这个数不是素数则被置0,置成其他的负数也一样,只是为了区分和统计
                //i + temp * i1,i是因为从当前数字开始,比如10是从5的位置开始计算位置
                nums[i + temp * i1] = 0;
            }
        }
    }
    return countNums(nums);
}

/**
 * 计算数组中的0出现了多少次
 *
 * @param nums
 * @return
 */
public static int countNums(int[] nums) {
    int size = nums.length;
    int zeros = 0;
    for (int num : nums) {
        if (num == 0) {
            zeros++;
        }
    }

    return size - zeros;
}

方法三

没必要把所有的数字都保存到一个数组里面,可以直接记录和数字对应的位置的数字是不是质数。如果不是质数,则在对应位置保存true.最后统计不是true的,即质数的个数即可。

这个方法可以通用下去。类似的统计的题目只记录对应的位置是否满足条件,最后统计符合条件的个数。

/**
 * 统计质数的数目。使用数组,用列表效率低。
 *
 * @param n
 * @return
 */
public static int countPrimes4(int n) {

    //n个元素的数组,其实只用到了n-2个。多见了2个防止输入0的时候崩溃。
    boolean[] nums = new boolean[n];
    //各种优化效率,只计算到sqrt(n)
    for (int i = 2; i * i < n; i++) {
        //获取数组中的数字是不是为0
        //不是质数则为true
        boolean temp = nums[i];
        //如果不是true,说明不是质数,则进行计算,否则直接跳过,因为这个数已经是之前的某数字的倍数
        if (!temp) {
            //把该数字的倍数都删去,因为他们都不是质数
            //int i1 = temp - 1  优化效率,是因为比如用5来删除数字的时候15=3*5已经被删除过了,所以从20=5*4开始删除
            for (int j = i; i * j < n; j++) {
                //如果这个数不是素数则被置true
                //i + temp * i1,i是因为从当前数字开始,比如10是从5的位置开始计算位置
                nums[i * j] = true;
            }
        }
    }
    return countNums2(nums);
}

/**
 * 计算数组中的不是素数的false出现了出现了多少次
 *
 * @param nums
 * @return
 */
public static int countNums2(boolean[] nums) {
    int notZeros = 0;
    for (int i = 2; i < nums.length; i++) {
        if (!nums[i]) {
            notZeros++;
        }
    }

    return notZeros;
}

Solution

托管在我的GitHub上:

https://github.com/fuxuemingzhu/CountPrimes

Captures

测试结果截图:

提交记录:

Reference

http://blog.csdn.net/blitzskies/article/details/45442923

https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#cite_note-horsley-1

http://blog.csdn.net/xudli/article/details/45361471

Date

2015/10/19 23:38:24

你可能感兴趣的:(LeetCode,less)