质数筛选法

来源:互联网 发布:淘宝会查物流重量吗 编辑:程序博客网 时间:2024/06/05 08:48

  近期刷题遇到质数的问题比较多,于是就去搜索了一些关于质数的问题,下面是我的一点总结,就作为学习知识的记录吧。下面是质数筛选的两种方法,学习算法的关键并不仅仅是知道这种方法,更多的是学习算法的思想,学习算法的策略,一个好的策略是非常关键的,它直接影响你算法的效率。

/** * 1.质数筛选法 : *  (1)埃拉托色尼筛法(时间复杂度O(nlogn)) *  (2)欧拉筛法 (时间复杂度O(n)) *  * 2.判断一个数是否是素数:(米勒罗宾测试) *  * 3.计算<=n的与n互质的数个数 *  * @author MG * */public class Primes {    /**     * 这个算法叫埃拉托色尼质数筛法(时间复杂度是O(nlogn),比传统方法快速的多)     *      * 由于一个合数总是可以分解成若干个质数的乘积,那么如果把质数(最初只知道2是质数)的倍数都去掉,那么剩下的就是质数了。     * 例如要查找100以内的质数,首先2是质数,把2的倍数去掉;此时3没有被去掉,可认为是质数,所以把3的倍数去掉;     *       再到5,再到7,7之后呢,因为8,9,10刚才都被去掉了,而100以内的任意合数肯定都有一个因子小于10(100的开方),     *    所以,去掉,2,3,5,7的倍数后剩下的都是质数了。     * 用程序可以这样解决,引入布尔类型数组a[i],如果i是质数,a[i]=true,否则a[i]=false。     * 那么去掉i可以表示成a[i]=false。     *      * @param n     */    public static void sieve(int n){        boolean[] assist = new boolean[n];        Arrays.fill(assist, true);        for(int i = 2;i < n;i ++){            if(assist[i]){                //注意这从i开始,不用从1开始                for(int j = i * i; j < n;j += i){                    assist[j] = false;                }            }        }    }    /**     * 质数欧拉筛法,时间复杂度(O(n) 每个数都会被判断一次) 上面方法中 : 30 在2 * 15 会被筛,在3 * 10也会被筛,在5 * 6 也会被筛(30被重复筛了多次)     *       *       * @param n     */    public static int elur(int n){        //标记是否为素数        boolean[] flags = new boolean[n];        int[] primes = new int[n];        int primeIndex = 0;        Arrays.fill(flags, true);        for(int i = 2; i < n; i++){            if(flags[i]){                primes[primeIndex ++] = i;            }            for(int j = 0; j < primeIndex; j++){                //判断是否超出范围                if(i * primes[j] > n) break;                flags[i * primes[j]] = false;                //每个数都是由它最小的质因数过滤掉(这句话很关键)                if(i % primes[j] == 0) break;            }        }        return primeIndex == 0 ? 0 : primeIndex - 1;    }    /**     * 假设 b很大,求a * b % n 的结果     *      * @param a     * @param b     * @param n     * @return     */    public static int getAmulBModN(int a, long b, int n) {        int res = 0;        while(b != 0){            if((b & 1) == 1) res = (res + a) % n;            a = (a + a) % n;            b >>= 1;        }        return res;    }    /**     * b很大,计算a^b % n的值     *      * @param a     * @param b     * @param n     * @return     */    public static int getAPowerBModN(int a, long b, int n){        int res = 1;        while(b != 0) {            if((b & 1) == 1) res = getAmulBModN(res, a, n);            a = getAPowerBModN(a, a, n);            b >>= 1;        }        return res;    }    /**     * 欧拉函数f(n):计算<=n的与n互质的数的个数     * f(x) = x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…(1-1/pn),其中p1,p2……pn为x的所有素因数     *      * 若m,n互质,f(m * n) = f(m) * f(n)     * 特殊性质:当n为奇数时 f(2 * n) = f(n), 证明与上述类似。     * 若n为质数则f(n) = n - 1      *      * @param n     * @return     */    public static int getCount(int n){        int res = n, a = n;        for(int i = 2; i * i <= n; i++) {            if(a % i == 0) {                //防止越界                res = res / i * (i - 1);                while(a % i == 0) a /= i;            }        }        //a剩下的如果不为1就肯定为质数        if(a > 1) res = res / a * (a - 1);        return res;    }    /**     * 得到1-n的欧拉函数值     *      * @param n     * @return     */    public static int[] getElur(int n){        int[] values = new int[n + 1];        values[1] = 1;        //公式中x*(1 - 1/p1)...中的x        for(int i = 2;i <= n; i++) {            values[i] = i;        }        for(int i = 2; i <= n; i++){            //values[i] == i : 证明i为质数            if(values[i] == i){                //后面每个都有i这个质因数                for(int j = i; j <= n; j += i){                    //先做除法是防止越界                    values[j] = values[j] / i * (i - 1);                }            }        }        return values;    }     /**     * @param args     */    public static void main(String[] args) {        // TODO Auto-generated method stub        System.out.println(getCount(10));    }}
0 0