Solution to Euler Project Task 5: Why does it work? - python

After some trial and error I have found a solution which works very quickly for the Project Euler Problem 5. (I have found another way which correctly solved the example case (numbers 1-10) but took an eternity to solve the actual Problem.) Here it goes:
def test(n):
for x in range(2,21):
if n % x != 0:
return False
return True
def thwart(n):
for x in range(2,21):
if test(n/x):
n /= x
return n
raise TypeError
num = 1
for x in range(1,21):
num *= x
while True:
try:
num = thwart(num)
except TypeError:
break
print(num)
My main problem is understanding why calling thwart(num) repeatedly is enough to result in the correct solution. (I.e. why is it able to find the SMALLEST number and doesnt just spit out any number divisible by the numbers 1-20?)
I only had some vague thoughts when programming it and was surprised at how quickly it worked. But now I have trouble figuring out why exactly it even works... The optimized solutions of other people on SO Ive found so far were all talking about prime factors which I can't see how that would fit with my program...?
Any help is appreciated! Thanks!

Well this isn't really a coding issue but a mathematical issue. If you look at all the numbers from 1-20 as the prime sthat make them you'll get the following:
1, 2,3,2^2,5,2^3,7,2^3....2^2*5.
the interesting part here is that once you multiply by the highest exponent of every single factor in these numbers you will get a number that can be divided by each of the numbers between one and twenty.
Once you realize that the problem is a simple mathematical one and approach it as such you can use this basic code:
import math
primes = [2]
for n in range(3,21): #get primes between 1 and 20
for i in primes:
if n in primes:
break
if n%i == 0:
break
if i> math.sqrt(n):
primes.append(n)
break
s = 1
for i in primes:
for j in range(10): # no reason for 10, could as well be 5 because 2^5 >20
if i**j > 20:
s = s*(i**(j-1))
break
print s
Additionally, the hint that the number 2520 is the smallest number that can be divided by all numbers should make you understand how 2520 is chosen:
I have taken a photo for you:
As you can caculate, when you take the biggest exponents and multiply them you get the number 2520.
What your solution does
your solution basically takes the number which is 1*2*3*4..*20 and tries dividing it by every number between 2 to 20 in such a way that it will still remain relevant. By running it over and over you remove the un-needed numbers from it. early on it will remove all the unnecessary 2's by dividing by 2, returning the number and then being called again and divided by 2 again. Once all the two's have been eliminated it will eliminate all the threes, once all the unnecessary threes will be eliminated it will try dividing by 4 and it will se it wont work, continue to 5, 6, 7... and when it finishes the loop without being able to divide it will raise a TypeError and you will finish your program with the correct number. This is not an efficient way to solve this problem but it will work with small numbers.

Related

Debugging in Hungarian Maximum Matching

I wrote a code to solve the following algorithm question:
Given a number of positive integers all larger than 1, find the maximum number of pairs whose sum is a prime number. The number of positive integers is always an even number.
For example, given 2 5 6 13 2 11, the answer is 3 since 2+5=7, 6+13=19, 2+11=13.
I wrote the following code to solve the problem. I know this is not the optimal algorithm, but I just cannot find the bug in it that results in my failure in test cases.
def _isPrime(num):
for i in range(2, int(num**0.5)+1):
if num % i==0:
return False
return True
def findPairs(odds, evens, pairDict):
if len(odds)==0 or len(evens)==0:
return 0
key=' '.join(list(map(str, odds+evens)))
if key in pairDict:
return pairDict[key]
n=0
for i in range(len(evens)):
newOdds=odds.copy()
newEvens=evens.copy()
del newOdds[0]
del newEvens[i]
if _isPrime(odds[0]+evens[i]):
n=max(n,findPairs(newOdds, newEvens, pairDict)+1)
else:
n=max(n,findPairs(newOdds, newEvens,pairDict))
pairDict[key]=n
return n
numbers=list(map(int,input().split()))
odds=[i for i in numbers if i%2==1]
evens=[j for j in numbers if j%2==0]
pairDict={}
print(findPairs(odds,evens,pairDict))
Can someone help me find where the problem is. Thanks a lot!
The problem is that the recursion always tries to match the first odd number with some even number. This can go wrong if there are fewer even numbers than odd numbers because it will use up an even number that could have been used for a later match.
For example, consider "13 2 3". This code will return 0, but 2+3 is a prime.
You could fix it by also allowing an extra recursion case where the first odd number is discarded without reducing the even list.
del newOdds[0]
n=max(n,findPairs(newOdds, newEvens, pairDict)) # added line
del newEvens[i]

Optimising code for finding the next prime number

I'm new to both Python and StackOverflow so I apologise if this question has been repeated too much or if it's not a good question. I'm doing a beginner's Python course and one of the tasks I have to do is to make a function that finds the next prime number after a given input. This is what I have so far:
def nextPrime(n):
num = n + 1
for i in range(1, 500):
for j in range(2, num):
if num%j == 0:
num = num + 1
return num
When I run it on the site's IDE, it's fine and everything works well but then when I submit the task, it says the runtime was too long and that I should optimise my code. But I'm not really sure how to do this, so would it be possible to get some feedback or any suggestions on how to make it run faster?
When your function finds the answer, it will continue checking the same number hundreds of times. This is why it is taking so long. Also, when you increase num, you should break out of the nested loop to that the new number is checked against the small factors first (which is more likely to eliminate it and would accelerate progress).
To make this simpler and more efficient, you should break down your problem in areas of concern. Checking if a number is prime or not should be implemented in its own separate function. This will make the code of your nextPrime() function much simpler:
def nextPrime(n):
n += 1
while not isPrime(n): n += 1
return n
Now you only need to implement an efficient isPrime() function:
def isPrime(x):
p,inc = 2,1
while p*p <= x:
if x % p == 0: return False
p,inc = p+inc,2
return x > 1
Looping from 1 to 500, especially because another loop runs through it, is not only inefficient, but also confines the range of the possible "next prime number" that you're trying to find. Therefore, you should make use of while loop and break which can be used to break out of the loop whenever you have found the prime number (of course, if it's stated that the number is less than 501 in the prompt, your approach totally makes sense).
Furthermore, you can make use of the fact that you only need check the integers less than or equal to the square root of the designated integer (which in python, is represented as num**0.5) to determine if that integer is prime, as the divisors of the integers always come in pair and the largest of the smaller divisor is always a square root, if it exists.

PYTHON: Finding an nth prime number

I've looked through a variety of older posts on this subject, and they have all left me confused in some way or another. So I'll start at the beginning.
The problem is #7 on Project Euler and I am a fairly new programmer trying to work my way through the problems. #7 is as follows.
By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13.
What is the 10,001st prime number?
My issue is as follows. I have a clear understanding of what prime numbers are and how they work. The sudo-code I would write for this problem is this:
For n in range(3,n) #where n is some very large value.
if n%i ==0 for i in range(2,n-1)
return False
if n%i == 0 for i == n
return True
But I think my lack of knowledge when it comes to Python is impeding me in finding what I want.
In most of the other solutions I have seen, they limit n to something like 125000 and I honestly have no clue where they came up with that number from.
The other issue is I don't know how to search properly through a range and create a list of values that satisfied that relation in a manner that I can then check the Max value in the list.
The thing that would make the most sense to me would be to basically append each new prime to a list and then just take the max value, but I'm sure there is a better and faster way to do this. If you are going to answer, please include a healthy dose of explanation without jumping into python technobabble, remember, I'm a beginner in programming.
I know that the typical way people deal with questions like this is to prod the asker into finding the right answer, I don't want that. I would like someone to show me a solution and then walk through it step by step explaining what each part of the code does so that I can learn not only how to solve the problem, but also gain a better intuition for how python works.
Thanks.
This task basically asks you to gather 10001 prime numbers. So start by building a list of primes and when you reach the 10001th number display it.
Here is a sample code:
def is_prime(n):
for i in range(3, n):
if n % i == 0:
return False
return True
primes = [] # list of primes
x = 10001 # go to the nth-number
n = 2 # start at number 2
while len(primes) != x+1: # is n-th number on the list? +1 is because list is zero-based
if is_prime(n):
primes.append(n) # add prime to the list
n+=1 # increment n to check the next number
# print the last item in the list - the n-th number
print(primes[-1])

Optimizing Prime Number Python Code

I'm relatively new to the python world, and the coding world in general, so I'm not really sure how to go about optimizing my python script. The script that I have is as follows:
import math
z = 1
x = 0
while z != 0:
x = x+1
if x == 500:
z = 0
calculated = open('Prime_Numbers.txt', 'r')
readlines = calculated.readlines()
calculated.close()
a = len(readlines)
b = readlines[(a-1)]
b = int(b) + 1
for num in range(b, (b+1000)):
prime = True
calculated = open('Prime_Numbers.txt', 'r')
for i in calculated:
i = int(i)
q = math.ceil(num/2)
if (q%i==0):
prime = False
if prime:
calculated.close()
writeto = open('Prime_Numbers.txt', 'a')
num = str(num)
writeto.write("\n" + num)
writeto.close()
print(num)
As some of you can probably guess I'm calculating prime numbers. The external file that it calls on contains all the prime numbers between 2 and 20.
The reason that I've got the while loop in there is that I wanted to be able to control how long it ran for.
If you have any suggestions for cutting out any clutter in there could you please respond and let me know, thanks.
Reading and writing to files is very, very slow compared to operations with integers. Your algorithm can be sped up 100-fold by just ripping out all the file I/O:
import itertools
primes = {2} # A set containing only 2
for n in itertools.count(3): # Start counting from 3, by 1
for prime in primes: # For every prime less than n
if n % prime == 0: # If it divides n
break # Then n is composite
else:
primes.add(n) # Otherwise, it is prime
print(n)
A much faster prime-generating algorithm would be a sieve. Here's the Sieve of Eratosthenes, in Python 3:
end = int(input('Generate primes up to: '))
numbers = {n: True for n in range(2, end)} # Assume every number is prime, and then
for n, is_prime in numbers.items(): # (Python 3 only)
if not is_prime:
continue # For every prime number
for i in range(n ** 2, end, n): # Cross off its multiples
numbers[i] = False
print(n)
It is very inefficient to keep storing and loading all primes from a file. In general file access is very slow. Instead save the primes to a list or deque. For this initialize calculated = deque() and then simply add new primes with calculated.append(num). At the same time output your primes with print(num) and pipe the result to a file.
When you found out that num is not a prime, you do not have to keep checking all the other divisors. So break from the inner loop:
if q%i == 0:
prime = False
break
You do not need to go through all previous primes to check for a new prime. Since each non-prime needs to factorize into two integers, at least one of the factors has to be smaller or equal sqrt(num). So limit your search to these divisors.
Also the first part of your code irritates me.
z = 1
x = 0
while z != 0:
x = x+1
if x == 500:
z = 0
This part seems to do the same as:
for x in range(500):
Also you limit with x to 500 primes, why don't you simply use a counter instead, that you increase if a prime is found and check for at the same time, breaking if the limit is reached? This would be more readable in my opinion.
In general you do not need to introduce a limit. You can simply abort the program at any point in time by hitting Ctrl+C.
However, as others already pointed out, your chosen algorithm will perform very poor for medium or large primes. There are more efficient algorithms to find prime numbers: https://en.wikipedia.org/wiki/Generating_primes, especially https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes.
You're writing a blank line to your file, which is making int() traceback. Also, I'm guessing you need to rstrip() off your newlines.
I'd suggest using two different files - one for initial values, and one for all values - initial and recently computed.
If you can keep your values in memory a while, that'd be a lot faster than going through a file repeatedly. But of course, this will limit the size of the primes you can compute, so for larger values you might return to the iterate-through-the-file method if you want.
For computing primes of modest size, a sieve is actually quite good, and worth a google.
When you get into larger primes, trial division by the first n primes is good, followed by m rounds of Miller-Rabin. If Miller-Rabin probabilistically indicates the number is probably a prime, then you do complete trial division or AKS or similar. Miller Rabin can say "This is probably a prime" or "this is definitely composite". AKS gives a definitive answer, but it's slower.
FWIW, I've got a bunch of prime-related code collected together at http://stromberg.dnsalias.org/~dstromberg/primes/

Trying to understand a solution to project Euler # 3

The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ? # http://projecteuler.net/problem=3
I have a deal going with myself that if I can't solve a project Euler problem I will understand the best solution I can find. I did write an algorithm which worked for smaller numbers but was too inefficient to work for bigger ones. So I googled Zach Denton's answer and started studying it.
Here is his code:
#!/usr/bin/env python
import math
def factorize(n):
res = []
# iterate over all even numbers first.
while n % 2 == 0:
res.append(2)
n //= 2
# try odd numbers up to sqrt(n)
limit = math.sqrt(n+1)
i = 3
while i <= limit:
if n % i == 0:
res.append(i)
n //= i
limit = math.sqrt(n+i)
else:
i += 2
if n != 1:
res.append(n)
return res
print max(factorize(600851475143))
Here are the bits I can't figure out for myself:
In the second while loop, why does he use a sqrt(n + 1) instead of just sqrt(n)?
Why wouldn't you also use sqrt(n + 1) when iterating over the even numbers in the first while loop?
How does the algorithm manage to find only prime factors? In the algorithm I first wrote I had a separate test for checking whether a factor was prime, but he doesn't bother.
I suspect the +1 has to do with the imprecision of float (I am not sure whether it's actually required, or is simply a defensive move on the author's part).
The first while loop factors all twos out of n. I don't see how sqrt(n + 1) would fit in there.
If you work from small factor to large factors, you automatically eliminate all composite candidates. Think about it: once you've factored out 5, you've automatically factored out 10, 15, 20 etc. No need to check whether they're prime or not: by that point n will not be divisible by them.
I suspect that checking for primality is what's killing your original algorithm's performance.

Categories