Project Euler Problem 51 (C++和Python)

版权声明:代码属于原创,转载请联系作者并注明出处。 https://blog.csdn.net/weixin_43379056/article/details/85095820

Problem 51: Prime digit replacements

By replacing the 1st digit of the 2-digit number *3, it turns out that six of the nine possible values: 13, 23, 43, 53, 73, and 83, are all prime.

By replacing the 3rd and 4th digits of 56**3 with the same digit, this 5-digit number is the first example having seven primes among the ten generated numbers, yielding the family: 56003, 56113, 56333, 56443, 56663, 56773, and 56993. Consequently 56003, being the first member of this family, is the smallest prime with this property.

Find the smallest prime which, by replacing part of the number (not necessarily adjacent digits) with the same digit, is part of an eight prime value family.

C++ 代码

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

using namespace std;

class PE0051
{
private:
    bool checkPrime(int number);
    bool getDigitsOfPrime(int prime, int numOfDigits, int numOfSameDigits, 
                          vector<int>& digit_v, int& sameDigit, 
                          vector<int>& sameDigit_pos);
    bool checkPosInVector(int pos, vector<int>pos_vec);

public:
    int getXdigitSmallestPrime(int numOfDigits, int numOfSameDigits,
                               int numOfPrimes);
};

bool PE0051::checkPrime(int number)
{
    long double squareRoot=sqrt((long double)number);

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

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

    return true;
}

bool PE0051::getDigitsOfPrime(int prime, int numOfDigits, int numOfSameDigits,
                              vector<int>& digit_v, int & sameDigit, 
                              vector<int>& sameDigit_pos)
{
    map<int, int> digits_mp;
    bool foundSameDigit = false;

    for (int i=numOfDigits-1; i>=0 && prime > 0; i--)
    {
        digits_mp[prime%10] += 1;
        digit_v[i] = prime%10;   // save all digits of the prime
        prime /= 10; 
    }
    
    map<int, int>::iterator iter = digits_mp.begin();
    for(;iter!=digits_mp.end();iter++)
    {
        if (digits_mp[iter->first] >= numOfSameDigits) // found all same digits 
        {
            foundSameDigit = true;
            sameDigit = iter->first;
            break;
        }
    }

    // 2-digit: *Z
    // 5-digit: XY**Z
    // 6-digit: *X*Y*Z
    for(int i=numOfDigits-1, j=numOfSameDigits-1; i>=0 && j>=0; i--)  
    {
        if (digit_v[i] == sameDigit)
        {
            sameDigit_pos[j] = i;  // save same digit position
            j--;
        }
    }

    if (sameDigit_pos[numOfSameDigits-1] == numOfDigits-1)
    {
        foundSameDigit = false; // last digit can not be position of same digit
    }

    return foundSameDigit;
}

bool PE0051::checkPosInVector(int pos, vector<int> pos_vec)
{
    vector<int>::iterator pos_vec_iter = pos_vec.begin();

    for( ;pos_vec_iter != pos_vec.end(); pos_vec_iter++)
    {
        if (pos == *pos_vec_iter)
        {
            return true;
        }
    }
    return false;
}

int PE0051::getXdigitSmallestPrime(int numOfDigits, int numOfSameDigits, 
                                   int numOfPrimes)
{
    vector<int> digitsVec(numOfDigits);            // all digits of prime
    vector<int> sameDigitsPosVec(numOfSameDigits); // same digits pos of prime
    int sameDigit = 0;

     // 2-digit: [10, 99], 5-digit: [ 10000, 99999], 6-digit: [100000...999999]
    int range_start = (int)pow(10.0, numOfDigits-1);
    int range_end   = (int)pow(10.0, numOfDigits) - 1;

    set<int> primes_set;
    set<int>::iterator ps_iter;

    for (int n=range_start; n<=range_end; n++) 
    {
        if (true == checkPrime(n))
        {
            primes_set.insert(n);

            if (true == getDigitsOfPrime(n, numOfDigits, numOfSameDigits, 
                                       digitsVec, sameDigit, sameDigitsPosVec))   
            {
                for (int i=sameDigit+1; i<=9; i++)
                {
                    int number = 0;

                    for(int j=0;j<numOfDigits;j++)
                    {
                        number *= 10;
                        if (true == checkPosInVector(j, sameDigitsPosVec))
                        {
                            number += i;
                        }
                        else
                        {
                            number += digitsVec[j];
                        }
                    }

                    if (true == checkPrime(number))
                    {
                        primes_set.insert(number); 
                    }
                }

                if (primes_set.size() == numOfPrimes)
                {
                    ps_iter = primes_set.begin();
#ifdef UNIT_TEST
                    copy(primes_set.begin(), primes_set.end(), 
                         ostream_iterator<int>(cout, "\t"));
                    cout << endl;
#endif
                    return *ps_iter;  // first prime in primes set
                }
            }

            primes_set.clear();
        }
    }

    return 0; 
}
    

int main()
{
    PE0051 pe0051;

    assert (13    == pe0051.getXdigitSmallestPrime(2, 1, 6));
    assert (56003 == pe0051.getXdigitSmallestPrime(5, 2, 7));

    cout << "8-digit first smallest prime is ";
    cout << pe0051.getXdigitSmallestPrime(6, 3, 8) << endl;

    return 0;
}

C++11 代码

#include <iostream>
#include <string>
#include <set>
#include <map>
#include <iterator>
#include <cmath>
#include <cassert>

using namespace std;

//#define UNIT_TEST

class PE0051
{
private:
    bool checkPrime(int number);
    int getSameDigitOfPrime(int prime, int numOfDigits, int numOfSameDigits);
    int replaceAllSameDigits(string s, int sameDigit, int newDigit);

public:
    int getXdigitSmallestPrime(int numOfDigits, int numOfSameDigits, 
                               int numOfPrimes);
};

bool PE0051::checkPrime(int number)
{
    long double squareRoot = sqrt((long double)number);

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

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

    return true;
}

int PE0051::getSameDigitOfPrime(int prime, int numOfDigits, int numOfSameDigits)
{
    map<int, int> digits_mp;
    int sameDigit = 0;

    for (int i = numOfDigits - 1; i >= 0 && prime > 0; i--)
    {
        digits_mp[prime % 10] += 1;
        prime /= 10;
    }

    map<int, int>::iterator iter = digits_mp.begin();
    for (; iter != digits_mp.end(); iter++)
    {
        if (digits_mp[iter->first] == numOfSameDigits)  
        {
            sameDigit = iter->first;  // found same digit
            break;
        }
    }

    return sameDigit;
}

int PE0051::replaceAllSameDigits(string s, int sameDigit, int newDigit)
{
    for (unsigned int i=0; i<s.size(); i++)
    {
        if (s[i] == (char)('0'+sameDigit))
        {
            s[i] = (char)('0'+ newDigit);
        }
    }
    return stoi(s);
}

int PE0051::getXdigitSmallestPrime(int numOfDigits, int numOfSameDigits,
                                   int numOfPrimes)
{
    // 2-digit: [10, 99], 5-digit: [ 10000, 99999], 6-digit: [100000...999999]
    int range_start = (int)pow(10.0, numOfDigits - 1);
    int range_end   = (int)pow(10.0, numOfDigits) - 1;

    set<int> primes_set;

    for (int n = range_start; n <= range_end; n++)
    {
        if (true == checkPrime(n))
        {
            primes_set.insert(n);

            int sameDigit = getSameDigitOfPrime(n, numOfDigits, numOfSameDigits);

            string digitsStr = to_string(n);

            for (int newDigit = sameDigit + 1; newDigit <= 9; newDigit++)
            {
                int number = replaceAllSameDigits(digitsStr, sameDigit, newDigit);

                if (true == checkPrime(number))
                {
                    primes_set.insert(number);
                }
            }

            if (primes_set.size() == numOfPrimes)
            {
#ifdef UNIT_TEST
                copy(primes_set.begin(), primes_set.end(), 
                     ostream_iterator<int>(cout, " "));
                cout << endl;
#endif
                return n;  // n is the first prime in primes set
            }
            primes_set.clear();
        }
    }

    return 0;
}
    
int main()
{
    PE0051 pe0051;

    assert(   13 == pe0051.getXdigitSmallestPrime(2, 1, 6));
    assert(56003 == pe0051.getXdigitSmallestPrime(5, 2, 7));

    int prime = pe0051.getXdigitSmallestPrime(6, 3, 8);
    cout << "8-digit first smallest prime is " << prime << "." << endl;

    return 0;
}

Python 代码

import re

def checkPrime(n):
    """
    check whether n is a prime
    """
    if n < 2 or n != 2 and n%2 == 0:
        return False

    for i in range(3, int(n**0.5)+1, 2):
        if 0 == n % i:
            return False
    
    return True

def getDigitsOfPrime(prime):
    """
    covert a prime to digits list
    """
    return [ int(digit) for digit in sorted(list(str(prime))) ]

def getXdigitSmallestPrime(numOfDigits, numOfPrimes):
    """
    get smallest prime with such property
    """
    for n in range(10**(numOfDigits-1), 10**numOfDigits):
        primes_list = []
        if True == checkPrime(n):
            primes_list.append(n)
            digits_list = getDigitsOfPrime(n)
            same_digit  = digits_list[0]
            s = str(n)
            for i in range(same_digit+1, 10):
                strinfo = re.compile(str(same_digit))
                ns = strinfo.sub(str(i), s)
                number = int(ns)
                if True == checkPrime(number):
                    primes_list.append(number)

        if numOfPrimes == len(primes_list):
            #print(primes_list)
            return primes_list[0]
        else:
            primes_list.clear()

    return 0

def main():
    assert    13 == getXdigitSmallestPrime(2, 6)
    assert 56003 == getXdigitSmallestPrime(5, 7)

    print("8-digit first smallest prime is",getXdigitSmallestPrime(6, 8))
    
if  __name__ == '__main__':
    main()

猜你喜欢

转载自blog.csdn.net/weixin_43379056/article/details/85095820
今日推荐