Leetcode题目总结-Math-如何判断素数?

来源:互联网 发布:百度云总显示网络异常 编辑:程序博客网 时间:2024/06/06 09:04

  今天做了一道很有意思的题目,leetcode上的204 Count primes.

  

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


  刚看到这道题目的时候,在想....小学生的题目,于是按照常规的判断方法即只能被1和本身这个数整除的数是素数。按照这个思路我写出了第一个解决方案。


  My Solution1:

  public int countPrimes(int n) {        if(n == 0 || n == 1) return 0;        //0和1不适素数                int count = 0;//纪录素数个数        boolean flag = true; //判断是否为素数的标志        for(int i = 2; i < n; i++ ){        //遍历n里面的所有数,来判断是否为素数            for(int j = 2; j < i; j++){                if(i%j == 0){                    flag = false;                    break;                }            }            if(flag) count ++;            flag = true;        }        return count;    }}

结果gg了,显示  time limit exceeded!


于是,想了想上述判断方法,明显存在效率极低的问题。对于每个数n,其实并不需要从2判断到n-1,我们知道,一个数若可以进行因数分解,那么分解时得到的两个数一定是一个小于等于sqrt(n),一个大于等于sqrt(n),据此,上述代码中并不需要遍历到n-1,遍历到sqrt(n)即可,因为若sqrt(n)左侧找不到约数,那么右侧也一定找不到约数。


  My Solution2:

  public int countPrimes(int n) {        if(n == 0 || n == 1) return 0;                int count = 0;        boolean flag = true;        for(int i = 2; i < n; i++ ){            for(int j = 2; j <= Math.sqrt(i);j++){                 if(i%j == 0){                    flag = false;                    break;                }            }            if(flag) count ++;            flag = true;        }        return count;    }}

  结果还是gg,time limit exceeded!


 这就说明最开始的思路是不对的。没办法,百度了一下这道题目用到了一个算法 埃拉托色尼筛法算法。
下面介绍一下这个算法。

1)先把1删除(现今数学界1既不是质数也不是合数)

2)读取队列中当前最小的数2,然后把2的倍数删去

3)读取队列中当前最小的数3,然后把3的倍数删去

4)读取队列中当前最小的数5,然后把5的倍数删去

5)如上所述直到需求的范围内所有的数均删除或读取(即某个素数的平方等于最后一个数


My Solution3:

public class Solution {    public int countPrimes(int n) {        if(n == 0 || n == 1) return 0;                boolean[] notprime = new boolean[n];        // 默认所有的元素值都会设置成false; boolean的初始值为false        notprime[0] = true;        notprime[1] = true;      //前两个数都不是素数                for(int i = 2; i * i < n; i++){  //当某个素数的平方等于或者大于n的时候,判断结束            if(!notprime[i]){ //如果I是素数,那么                for(int j = 2; i * j < n; j++){                     notprime[i*j] = true;                }            }        }                int count = 0;        for(boolean notP : notprime){            if(!notP) count++;        }                return count;            }}

跑下来其实效率也不是很高,后面我发现有重复的地方:

 for(int i = 2; i * i < n; i++){            if(!notprime[i]){                 for(int j = 2; i * j < n; j++){ //这里有大量的数字重复,比如当i=2时候,j =2,3,...;当i=3是,j= 2,3,..                    notprime[i*j] = true; //此时2*3在i = 2时候已经判断过; i = 3没有必要再判断。                }            }        }        

改正为:


 for(int i = 2; i * i < n; i++){              if(!notprime[i]){                 for(int j = i; i * j < n; j++){                     notprime[i*j] = true;                }            }        }

 这样就好了!!!!



原创粉丝点击