Project Euler Problem 35 (C++和Python)

100 篇文章 3 订阅
87 篇文章 1 订阅

Problem 35 : Circular primes

The number, 197, is called a circular prime because all rotations of the digits: 197, 971, and 719, are themselves prime.

There are thirteen such primes below 100: 2, 3, 5, 7, 11, 13, 17, 31, 37, 71, 73, 79, and 97.

How many circular primes are there below one million?

#include <iostream>
#include <vector>
#include <set>
#include <iterator>
#include <cmath>
#include <ctime>
#include <cassert>

using namespace std;

// #define UNIT_TEST
// #define USE_DIGITS_VECTOR

class PE0035
{
private:
    static const int m_MAX = 1000000;  // one millions
    bool *m_Sieve;

    void createPrimeSieve();
    bool checkPrime(long long number);
    bool checkDigitZero(int number);
    vector<int> getDigits(long int number);
    long getNumberByDigits(vector<int>& digits);
    bool checkRotationDigits(long int number);

public:
    PE0035() { m_Sieve = new bool [m_MAX+1]; createPrimeSieve(); }
    ~PE0035() { delete [] m_Sieve; }

    int getCircularPrimes(int number);
};

// create a prime Sieve of Eratosthenes below max value
void PE0035::createPrimeSieve()
{
    memset(m_Sieve, true, (m_MAX+1)*sizeof(bool)); 

    m_Sieve[0] = m_Sieve[1] = false;

    for (int i=2; i<=(int)sqrt((double)m_MAX); i++) 
    {
        if (true == m_Sieve[i]) 
        {
            for (int j=i*i; j<m_MAX; j+=i)
            {
                m_Sieve[j] = false;
            }
        }
    }
}

bool PE0035::checkPrime(long long number)
{
    long double squareRoot=sqrtl((long double)number);

    if (number<2 || number%2 == 0 && number>2)
    {
        return false;
    }

    for(long int i=3;i<=(long long)squareRoot;i+=2)  // 3, 5, 7, ...(int)squareRoot
    {
        if (number % i == 0)
        {
            return false;
        }
    }

    return true;
}

vector<int> PE0035::getDigits(long int number)
{
    vector<int> digit_vec;

    while(number> 0)
    {
        digit_vec.push_back(number%10);  // 197 => reverse digits: 7, 9, 1
        number /= 10; 
    }

    return digit_vec;
}

long PE0035::getNumberByDigits(vector<int>& digits)
{
    vector<int>::reverse_iterator iter=digits.rbegin();
    long number = 0;

    while(iter!=digits.rend())                  
    {
        number = number*10 + *iter;  // digits: 7, 9, 1  => 197
        iter++;
    }

    return number;
}

bool PE0035::checkRotationDigits(long int number)
{
#ifdef USE_DIGITS_VECTOR

    if (number > 10)
    {
        vector<int> digits_v;
        while(number> 0)
        {
            if (0 == number%10)
            {
                return false;
            }
            digits_v.push_back(number%10);  // 197 => digits: 7, 9, 1
            number /= 10; 
        }

        vector<int>::iterator iter;
        int digit;

        for(unsigned int i=1; i<digits_v.size(); i++)
        {
            iter   = digits_v.begin();
            digit  = *iter;
            digits_v.erase(iter);
            digits_v.push_back(digit);
            number = getNumberByDigits(digits_v);
            if (false == m_Sieve[number])
            {
                return false;
            }
        }
    }

#else  // USE_DIGITS_ARRAY

    int digitsArray[6]; // max number 999999
    int numOfDigits = 0;
    while (number > 0)
    {
        if (0 == number%10)
        {
            return false;
        }
        digitsArray[numOfDigits++] = number%10;
        number /= 10;
    }

    // note that digitsArray stores reverse digits of number
    // digitsArray[] = {1, 3, 3, 9, 9, 9} while number is 999331
    for (int i=numOfDigits-1; i>0; i--)
    {
        number = 0;
        for (int j=numOfDigits+i-1; j>=i; j--)
        {
            number = number*10 + digitsArray[j%numOfDigits];
        }
        if (false == m_Sieve[number])
        {
            return false;
        }
    }
#endif

    return true;
}

int PE0035::getCircularPrimes(int number=m_MAX)
{
    int numOfCircularPrimes = 0;

    for(long n=2; n<number; n++)
    {
        if (true==m_Sieve[n] && true==checkRotationDigits(n))
        {
#ifdef UNIT_TEST
            cout << "The number " << n << " is called a circular prime." << endl;
#endif
            numOfCircularPrimes++;
        }
    }

    return numOfCircularPrimes;
}

int main()
{
    clock_t start = clock();

    PE0035 pe0035;

    assert(13 == pe0035.getCircularPrimes(100));
    
    cout << "There are " << pe0035.getCircularPrimes();
    cout << " circular primes below one million" << endl;

    clock_t finish = clock();
    double duration = (double)(finish - start) / CLOCKS_PER_SEC;
    cout << "C/C++ application running time: " << duration << " seconds" << endl;

    return 0;
}
 

Python source code

def createPrimeSieve(n):
    """ 
    create prime sieve
    """
    sieve = [True] * n
    sieve[0] = sieve[1] = False

    for i in range(2, int(n**0.5)+1):
        if True == sieve[i]:
            for j in range(i*i, n, i):
                sieve[j] = False

    return sieve

def checkRotationDigits(number, primes_sieve):
    """
    check all rotated digits of number 
    """
    if False == primes_sieve[number]:
        return False

    digitsList = list(map(int, str(number)))

    for i in range(1, len(digitsList)):
        rotatedDigitsList = digitsList[i:] + digitsList[:i]
        s = ''
        for j in rotatedDigitsList:
            s += str(j) 
        number = int(s)
        if False == primes_sieve[number]:
            return False

    return True
    
def getCircularPrimes(number):
    """
    find all circular primes below number
    """
    primes_sieve = createPrimeSieve(number)
    numOfCircularPrimes = 0
    for n in range(2, number):
        if True == checkRotationDigits(n, primes_sieve):
            numOfCircularPrimes += 1

    return numOfCircularPrimes
   
def main():
    assert 13 == getCircularPrimes(100)
    print("There are",getCircularPrimes(10**6),"circular primes below one million");

if  __name__ == '__main__':
    main()
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值