leetcode [Count Primes]

来源:互联网 发布:海关出口数据怎么查询 编辑:程序博客网 时间:2024/06/08 13:11

错误解法:遇到大数会超时,因为时间复杂度是O(N^1.5)

public class Solution {public boolean isPrime(int n){boolean res = true;for(int i = 2; i <= (int)Math.sqrt(n); i++){//设计的时候循环控制条件一步步优化:从i <n,到i<=n/2,到i≤sqrt(n)if(n % i == 0){return false;}}return res;}    public int countPrimes(int n) {//质数定义在大于1的自然数中        int res = 0;        for(int i = 2; i < n; i++){        if(isPrime(i)){        res++;        }        }        return res;    }}

正确解法:

public class Solution {    public int countPrimes(int n) {//运用埃拉托色尼筛选法,时间复杂度为O(nlog(logn))    /*具体思路:     * [1] We start off with a table of n numbers. Let's look at the first number, 2.      *    We know all multiples of 2 must not be primes, so we mark them off as non-primes.      *     Then we look at the next number, 3. Similarly, all multiples of 3 such as 3 × 2 = 6, 3 × 3 = 9, ... must not be primes,      *     so we mark them off as well. Now we look at the next number, 4, which was already marked off.      *     What does this tell you? Should you mark off all multiples of 4 as well?     * [2] 4 is not a prime because it is divisible by 2, which means all multiples of 4 must also be divisible by 2 and      *     were already marked off. So we can skip 4 immediately and go to the next number,      *     Now, all multiples of 5 such as 5 × 2 = 10, 5 × 3 = 15, 5 × 4 = 20, 5 × 5 = 25, ... can be marked off.      *     There is a slight optimization here, we do not need to start from 5 × 2 = 10. Where should we start marking off?     * [3] In fact, we can mark off multiples of 5 starting at 5 × 5 = 25, because 5 × 2 = 10 was already marked off by multiple of 2,     *     similarly 5 × 3 = 15 was already marked off by multiple of 3. Therefore, if the current number is p,      *     we can always mark off multiples of p starting at p2, then in increments of p: p2 + p, p2 + 2p, ...      *     Now what should be the terminating loop condition?     * [4] It is easy to say that the terminating loop condition is p < n, which is certainly correct but not efficient.      *     Do you still remember Hint #3?(以sqrt(n)作为循环控制点)     * [5] Yes, the terminating loop condition can be p < √n, as all non-primes ≥ √n must have already been marked off.      *     When the loop terminates, all the numbers in the table that are non-marked are prime.     *     The Sieve of Eratosthenes(埃拉托色尼筛选法) uses an extra O(n) memory and its runtime complexity is O(n log log n).     */    //遍历一圈前n个数,对是素数的做一个标记    //做标记可以用Map<Integer, Boolean>,但是用boolean a[n]显然更方便,数组这种标记方式很有效    boolean[] isPrime = new boolean[n];//对比上面超时的解法,快就快在不是用方法isPrime,而是用数组isPrime先标记好了,这就相当于一个哈希表    for(int i = 0; i < isPrime.length; i++){//初始化数组    isPrime[i] = true;    }    for(int i = 2; i <= (int)Math.sqrt(n); i++){    if(!isPrime[i]){//比上面超时的解法快在这里    continue;//i不为素数时(i有因子a或b),说明在之前a或b的循环中已经标记过了,这里不必重复标记,跳过    }    //i为素数时,以i为因子的数一定是素数,因为有因子了    for(int j = i * i; j < n; j += i){//不写int j = i + i(从2j开始),见上面思路[3],这里也能提高速度    //本来循环中增量是i,则O(logn),因为这里j是从i*i开始,则O(log(logn))    isPrime[j] = false;    }    }            int res = 0;        for(int i = 2; i < n; i++){//质数定义在大于1的自然数中        if(isPrime[i]){        res++;        }        }        return res;    }}



0 0
原创粉丝点击