1

This is the problem I'm trying to solve.

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?

This is my attempt. I first put all prime numbers below 1000000 in a list called primes then calculated all their possible permutations and stored those permutations in a list. Then I checked whether those permutations are prime or not.

import math
def isPrime(num):
    flag = 1
    root = int(math.sqrt(num) + 1)
    for i in range (2,root+1):
        if num%i == 0:
            flag = 0
            break
        else:
            flag = 1
    if flag == 1:
        return True
    else:
        return False

primes = [#list of all primes below 1000000]

def permutations(word):
    if len(word) == 1:
        return [word]
    char = word[0]
    perms = permutations(word[1:])
    result = []
    for perm in perms:
        for i in range (len(perm)+1):
            result.append(perm[i:] + char + perm[:i])
    return result

count = 0
for i in primes:
    to_be_tested = permutations(str(i))
    count_to_be_fulfilled = len(to_be_tested)
    new_count = 0
    for j in to_be_tested:
        if isPrime(int(j)):
            new_count += 1
    if new_count == count_to_be_fulfilled:
        count += 1
print(count)

I get the answer 22 and according to Project Euler it's wrong. I don't know the answer as I want to solve this on my own and don't want to cheat. Please tell me what I'm doing wrong.

Riptide
  • 326
  • 2
  • 9
  • Also this code takes about 5 mins to execute so if there's a more efficient way, please tell me. – Riptide Apr 13 '19 at 10:39
  • 1
    I don't have time to go through the code but if you use sets instead of lists it will be faster – Kacper Floriański Apr 13 '19 at 11:08
  • And since you already have primes in a list (or a set if you change it) you can just check if a number is in that data structure to test if it's prime – Kacper Floriański Apr 13 '19 at 11:09
  • Agree with @Kacper on using sets. Have a look here for speeding up listing primes: https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n?rq=1. For your permutations function, I think you could simplify it by using strings to cycle one digit from front to back n times (where n is the length of the prime). Use the simplified function to create a set of potential circular primes, and use intersections to check whether that set is indeed a set of primes. – Berenger Apr 13 '19 at 16:28
  • This question only concerns **rotations**, so why are you generating (and testing) all of the permutations of a candidate number? Did you run your code for the example prime number 197 shown in the question? – ottomeister Apr 14 '19 at 01:04
  • You can quickly eliminate a lot of numbers from your `primes` by looking at the digits. Primes like 859 or 2731 can immediately be eliminated by inspection. That cuts down the number of possibles you have to test to about 1200. – rossum Apr 15 '19 at 11:31

1 Answers1

0

Solution

I will not post the full solution, because from the Project Euler's about section:

I learned so much solving problem XXX so is it okay to publish my solution elsewhere?

It appears that you have answered your own question. There is nothing quite like that "Aha!" moment when you finally beat a problem which you have been working on for some time. It is often through the best of intentions in wishing to share our insights so that others can enjoy that moment too. Sadly, however, that will not be the case for your readers. Real learning is an active process and seeing how it is done is a long way from experiencing that epiphany of discovery. Please do not deny others what you have so richly valued yourself.

However, I will give you a few tips.

Data structures

As I have mentioned in the comment, using sets will improve your program's performance a whole lot, because access to the data in those is really quick (you can check why by googling a technique called hashing if you don't know about it). Precisely, the performance with lists will be O(N) whereas with sets it will be about O(1).

Rotations vs permutations

In the problem statement, you are required to calculate the rotations of a number. As pointed out by @ottomeister, you should really check whether your program is doing what the problem statement expects it to be doing. Currently, calling permutations("197") will return the following list - ['791', '917', '179', '971', '719', '197'] - whereas the problem expects the result to be ['197', '971', '719']. Rather than creating permutations, you should compute rotations, which can be found for example by moving each digit to the left (with wrapping around) until the initial number is returned (could make a recursive algorithm like that if you really like those).

Prime checking

You are currently checking if each number is prime by performing a loop which checks if the number N is divisible by everything up to sqrt(N). As you have noticed, this is quite slow for a lot of numbers, and there are better ways to check if a number is prime. In your scenario, the ideal solution is to simply do N in primes because you already have generated the primes, which, if you use sets instead of lists, will be O(1). Alternatively, you can have a look at primality tests (especially the heuristic and probabilistic tests)

Finally

I generally recommend testing your own solution before everything else, you could have easily spotted that your permutations function is not meeting the problem statement's expected results at all. I suggest to break things further into smaller functions, for example you could have a rotations(number) function similar to your permutations, maybe a is_circular(number) function which checks if the given number meets problem requirements and count_circular(upper_bound) function which computes and counts the circular numbers. If you also comment everything as you go, it will make debugging things a lot easier and you will be able to confirm everything works as expected on the go :)

Kacper Floriański
  • 1,092
  • 7
  • 18