关于素数的算法小结

1. 判断一个数是不是素数

解法1:最经典的版本


  1 #include <stdio.h>
  2 #include <math.h>
  3 #include <stdbool.h>  //C99 supports bool type
  4 
  5 bool is_prime(int n) {
  6     if (n <= 3) return n > 1;
  7     int sqrt_n = sqrt(n);
  8 
  9     for (int i = 2; i <= sqrt_n; ++i) {
 10         if (n % i == 0) return false;
 11     }
 12 
 13     return true;
 14 }
 15 
 16 int main()
 17 {
 18     int n;
 19     while(~scanf("%d", &n)) {
 20         printf("%d is_prime() = %d\n", n, is_prime(n));
 21     }
 22     return 0;
 23 }

解法2:参考自https://blog.csdn.net/afei__/article/details/80638460

思路是:质数有一个特点,就是它总是等于 6x-1 或者 6x+1,其中 x 是大于等于1的自然数。
证明:首先 6x 肯定不是质数,因为它能被 6 整除;其次 6x+2 肯定也不是质数,因为它还能被2整除;依次类推,6x+3 肯定能被 3 整除;6x+4 肯定能被 2 整除。那么,就只有 6x+1 和 6x+5 (即等同于6x-1) 可能是质数了。所以循环的步长可以设为 6,然后每次只判断 6 两侧的数即可。也即,我们对n,从5到sqrt(n),挨个判断5,7,11,13,17,19...是不是可以被n整除就可以了。

 16 bool is_prime_v2(int n) {
 17     if (n <= 3) return n > 1;
 18 
 19     if (n % 6 != 1 && n % 6 != 5) {
 20         return false;
 21     }
 22 
 23     int sqrt_n = sqrt(n);
 24     for (int i = 5; i <= sqrt_n; i += 6) {
 25         if (n % i == 0 || n % (i + 2) == 0) {
 26             return false;
 27         }
 28     }
 29     return true;
 30 }

2. 判断小于n的prime数的数目
LintCode 1324. countPrimes.

解法1:普通筛法

class Solution {
public:
    /**
     * @param n: a integer
     * @return: return a integer
     */
    int countPrimes(int n) {
        if (n == 1) return 0;
        int sqrtn = sqrt(n);
        vector<int> filter(n, 1);
        
        for (int i = 2; i <= sqrtn; ++i) {
            int j = i << 1;
            while (j < n) {
                filter[j] = 0;
                j += i;
            }
        }
        int count = 0;
        for (int i = 1; i <= n; ++i) {
            if (filter[i] == 1) {
                count++;
            }
        }
        
        return count - 1;   //1 is not prime
    }
};

普通筛法的另一个版本:
当n>=46350后会出错,因为n*n>MAX_INT

class Solution {
public:
    /**
     * @param n: a integer
     * @return: return a integer
     */

    int countPrimes(int n) {
        vector<int> flags(n + 1, 0);
        for (int i = 2; i <= n; ++i) {
            if (flags[i]) continue;
            //fails after i >=46350 as i*i exceeds MAX_INT
            for (int j = i * i; j <= n; j += i) {
                flags[j] = 1;
            }
        }
        int count = 0;

        
        for (int i = 2; i < n; ++i) {
            if (!flags[i]) count++;
        }
        return count;   //1 is not prime
    }
};

解法2:线性筛。。时间复杂度O(n)。
关于线性筛法的介绍见 https://zhuanlan.zhihu.com/p/42609585
 

class Solution {
public:
    /**
     * @param n: a integer
     * @return: return a integer
     */

    int countPrimes(int n) {
        vector<int> primes(n + 1, 0); //primes[i]: 0 => unprocessed, -1 => non-prime, >0 => a prime-number
        int count = 0;
        for (int i = 2; i < n; ++i) {
            if (!primes[i]) {
                primes[count++] = i;
            }
            for (int j = 0; j < count; ++j) {
                int product = primes[j] * i;
                if (product > n) break;
                primes[product] = -1; //just show it is not prime-number. It can be any number except 0.
                if (i % primes[j] == 0) break;
            }
        }
        return count;
    }
};

3. 质因数分解

LintCode 1295: Given a positive integer N, you need to factorize all integers between (1, N]. Then you have to count the number of the total prime numbers.

解法1: DP,时间复杂度是O(n * sqrt(n))。

class Solution {
public:
    /**
     * @param N: a number
     * @return: the number of prime numbers.
     */
    int Count_PrimeNum(int N) {
        int result = 0;
        vector<int> records(N + 1, 1);
        records[0] = 0, records[1] = 0;
        for (int i = 2; i <= N; ++i) {
            result += records[i];
                int count = N / i;
                for (int j = 1; j <= count; ++j) {
                    records[i * j] = records[i] + records[j];
                }
        }
        
        return result;
    }
};
 

解法2:基于Pollard_Rho算法,注意Pollard_Rho算法时间复杂度O(n^ 1/4),所以总的时间复杂度是O(n^ 5/4)。
 

class Solution {
public:
    /**
     * @param N: a number
     * @return: the number of prime numbers.
     */
    int Count_PrimeNum(int N) {
        int result = 0;
        vector<int> nums(N + 1, -1);
    
        for (int i = 2; i <= N; ++i) {
            result += Pollard_Rho(i);
        } 
        return result;
    }
    
private:
    int Pollard_Rho(int n) {
        int count = 0;
        //vector<int> result;
        int sqrtn = sqrt(n);
        for (int i = 2; i <= sqrtn;) {
            while (n % i == 0) {
                count++;
             //   result.push_back(i);
                n /= i;
            }
            
            if (i == 2) i += 1;
            else i += 2;
        }
      //  if (count == 0) count = 1;  // if n is non-2 prime
        if (n > 1) count++;
        return count;
    }
};

4. 丑数类题目
这类题目都是说有n个素数,然后让你求第k个丑数。算法就是给每个素数一个指针,然后n个指针挨个挨个试,看哪个素数的倍数最小。
LeetCode 313. Super Ugly Number

Write a program to find the nth super ugly number.

Super ugly numbers are positive numbers whose all prime factors are in the given prime list primes of size k.

Example:

Input: n = 12, primes = [2,7,13,19]
Output: 32 
Explanation: [1,2,4,7,8,13,14,16,19,26,28,32] is the sequence of the first 12 
             super ugly numbers given primes = [2,7,13,19] of size 4.

Note:

  • 1 is a super ugly number for any given primes.
  • The given numbers in primes are in ascending order.
  • 0 < k ≤ 100, 0 < n ≤ 106, 0 < primes[i] < 1000.
  • The nth super ugly number is guaranteed to fit in a 32-bit signed integer.
class Solution {
public:
    int nthSuperUglyNumber(int n, vector<int>& primes) {
        int num = primes.size();
        vector<int> indexes(num, 1); 
        vector<int> uglys(n + 1);
        uglys[1] = 1;
        for (int i = 2; i <= n; ++i) {
            int candidate = uglys[indexes[0]] * primes[0];
           // int candidate_index = 0;
            for (int j = 1; j < num; ++j) {
                int temp = uglys[indexes[j]] * primes[j];
                if (candidate > temp) {
                    candidate = temp;
                    //candidate_index = j;
                }
            }
           
            for (int j = 0; j < num; ++j) {
                if (candidate == (uglys[indexes[j]] * primes[j])) {
                   indexes[j]++;                    
                }
            }
            uglys[i] = candidate;

        }
        return uglys[n];
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值