Python: ProjectEuler Q.5 - python

I'm trying to solve the following question: What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20? The problem is that I get a MemoryError. Is there a better way to do this, using the same logic?
for n in range(1,1000000000):
count = 0
for i in range(1,21):
if n%i == 0:
count = count + 1
if count == 20:
print n
Thanks

Assuming you're using Python 2, range allocates a list.
Utilize Python's lazy abilities with generators* , and use xrange instead.
for n in xrange(1,1000000000):
count = 0
for i in xrange(1,21):
if n%i == 0:
count = count + 1
if count == 20:
print n
That should solve your memory error. That said, there is a much faster solution to that particular problem (however, you asked for 'using the same logic').
* actually, a sequence object

Related

Find minimal operations such that N will become 1 with 3 operations

We are given N as a natural number and we can do these 3 operations with him.
1)Subtract 1 from N
2)If it is even, divide by 2
3)If it divides 3, then divide by 3
We stop this when N becomes 1. We need to find minimal operations such that N will become 1
#!/bin/python3
import math
import os
import random
import re
import sys
#
# Complete the 'count' function below.
#
# The function is expected to return an INTEGER.
# The function accepts INTEGER num as parameter.
#
def count(num):
count = 0
while num != 1:
if (num % 3 ==0 ):
count += 1
num = num / 3
elif((num -1) % 3 == 0):
count += 2
num = (num - 1) / 3
elif (num % 2 ==0):
count += 1
num = num / 2
else:
num = num - 1
count += 1
return count
This is my code. From 11 test cases it passed 9 and gave 2 wrong answers. I don't know for which test cases my code gives wrong answers. Can you help to understand where is problem?
You make an assumption that it is better to subtract 1 and divide by 3 first if you can, but that isn't always true.
Consider 16
Your solution would be 16-15-5-4-3-1 = 5 steps
Better solution:
16-8-4-2-1 = 4 steps
Probably not the most efficient solution but:
def count(num):
count1, count2 = float('inf'), float('inf')
if num == 1:
return 0
if num % 3 == 0:
count1 = 1 + count(num // 3)
if num % 2 == 0:
count2 = 1 + count(num // 2)
count3 = 1 + count(num - 1)
return min(count1, count2, count3)
These types of problems usually have a small set of rules that produce the optimal answer.
Your fundamental problem, though, is that you are assuming that your rule set is optimal with no evidence whatsoever. You really have no reason to believe that it will produce the right count.
Unfortunately, answers to these kinds of questions on SO sometimes provide the correct rule set, but always seem to omit any kind of proof that the rule set is optimal.
You have to do something that is guaranteed to work, so unless you have that kind of proof, you should fall back on an A* search or similar.
You may use the non-recursive breadth-first strategy.
Say there is a queue holding lists of numbers. Initially, enter a list holding just N into the queue. Then repeat the following until the queue is empty:
Pick the first list in the queue.
Repeat 3 for all three operations.
Select an operation. If possible, apply it to the last list number and add the result to the end of the list. If the list is a solution, store it somewhere. If not, add it to the end of the queue.
This strategy is exhaustive and finds all solutions. Since only the minimum is of interest, we introduce a limiting bound. Once a solution list is available, we do not enter lists longer than that into the queue, nor do we consider them if they are in the queue already.

Find max value in for loop range - Python

I've been working on a small program that takes the input of two numbers and gives the greatest common divisor. I have managed to get the program to at least print out all common divisors until the greatest number is reached, but all I need to print is the max value. Unfortunately, I can't get seem to get this to work. I've tried passing i though max() but was received an error that ''int' objects are not iterable''. Thus I am wondering if anyone could help me find a solution that will allow me to print only the max value as opposed to all values without having to employ much more complex coding methods. Here is the code
def great_divisor():
m = int(raw_input("Choose a number"))
n = int(raw_input("Choose another number"))
#lowest number assigned to d
if m > n:
d = n
else:
d = m
for i in range(1, d + 1):
if (n%i == 0 and m%i == 0):
print(max(i))
return
The easiest way is to use range(d, 0, -1) and just return the first divisor you find. No need to use max.
How about this?
maxn = 0
for i in range(1, d + 1):
if (n%i == 0 and m%i == 0):
maxn = i
return maxn
Max can only be applied to an iterable, a list for example.
You can add all the common divisor in a list and get the max.
for i in range(1, d + 1):
if (n%i == 0 and m%i == 0):
divisors.append(i)
print(max(divisors))

Euler Project #3 in Python

I'm trying to solve the Project Euler problem 3 in Python:
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?
I know my program is inefficient and oversized, but I just wanted to know why doesn't it work?
Here's the code:
def check(z):
# checks if the given integer is prime
for i in range(2, z):
if z % i == 0:
return False
break
i = i+1
return True
def primegen(y):
# generates a list of prime integers in the given range
tab = []
while y >= 2:
if check(y) == True:
tab.append(y)
i = i-1
def mainfuntion(x):
# main function; prints the largest prime factor of the given integer
primegen(x)
for i in range(len(tab)):
if x % tab[i] == 0:
print tab[i]
break
mainfuntion(600851475143)
And here's the error:
for i in range(2, z):
OverflowError: range() result has too many items
The reason is that a list in Python is limited to 536,870,912 elements (see How Big can a Python Array Get?) and when you create the range in your example, the number of elements exceeds that number, causing the error.
The fun of Project Euler is figuring out the stuff on your own (which I know you're doing :) ), so I will give one very small hint that will bypass that error. Think about what a factor of a number is - you know that it is impossible for 600851475142 to be a factor of 600851475143. Therefore you wouldn't have to check all the way up to that number. Following that logic, is there a way you can significantly reduce the range that you check? If you do a bit of research into the properties of prime factors, you may find something interesting :)
This is the code that I used!!
n = 600851475143
i = 2
while i * i < n:
while n % i == 0:
n = n / i
i = i + 1
print n
-M1K3
#seamonkey8: Your code can be improved. You can increase it by 2 rather than one. It makes a speed difference for really high numbers:
n,i = 6008514751231312143,2
while i*i <= n:
if n%i == 0:
n //= i
else:
i+=[1,2][i>2]

Python "OverflowError" [duplicate]

This question already has answers here:
`xrange(2**100)` -> OverflowError: long int too large to convert to int
(5 answers)
Closed 13 days ago.
I am just starting to learn to code in Python. I am trying to write some code to answer this Project Euler Question:
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?
My program works with the test case of 13195, but when I try to enter 600851475143, I get the error: "OverflowError: range() results has too many items"
Does anyone know how I can fix this?
Here is my code:
class Euler3:
"A class to find the largest prime factor of a given number"
n = 600851475143
primeFactors = []
for i in range(2,n):
if (n%i ==0):
primeFactors.append(i)
n = n/i
i = i -1 #reset i
print primeFactors
Any help or suggestions would be much appreciated!
The range function creates a list and tries to store it in memory. Creating a list many numbers long is what's causing the OverflowError. You can use xrange instead to get a generator which produces the numbers on demand.
That said, I think you'll find that your algorithm is way too slow for calculating large primes. There are a lot of prime number algorithms, but I might suggest checking out the Sieve of Eratosthenes as a starting point.
EDIT: Properly xrange actually doesn't return a generator, but an xrange object which behaves a lot like a generator. I'm not sure if you care, but it was bugging me that i wasn't precise!
I'm guessing you're using python 2 and not python 3 -- range(2,n) actually constructs a list! You don't have enough memory to store 600 billion numbers! xrange should be fine, though.
Also, your idea of i=i-1 doesn't work. For loops don't work like C, and that hack only works in C-style loops. The for loop iterates over range(2,n). If i gets the value 5 at once iteration, then no matter what you do to i, it still gets 6 the next time through.
Also, the list range(2,n) is constructed when you enter the loop. So when you modify n, that doesn't change anything.
You're going to have to rethink your logic a bit.
(if you don't believe me, try using 175 as a test case)
As a last comment, you should probably get in the habit of using the special integer division: n = n // i. Although / and // work the same in python 2, that is really deprecated behavior, and they don't work the same in python 3, where / will give you a floating point number.
You can fix the problem by using xrange instead of range
Your next problem will be that the program takes way too long to run because you need to break out of the loop under some condition
A better way to deal with repeat factors is to replace the if with a while
while (n%i ==0):
primeFactors.append(i)
n = n/i
n = 600851475143
primeFactors = []
for i in range(2,n):
i think you can optimize the function by noticing that
for i in range(2,n):
you can replace
range(2,n)
by
range(2,int(sqrt(n))+2)
because, you can see wiki...
This is the best way to find primes that I've found so far:
def isprime(n):
#make sure n is a positive integer
n = abs(int(n))
#0 and 1 are not primes
if n < 2:
return False
#2 is the only even prime number
if n == 2:
return True
#all other even numbers are not primes
if not n & 1:
return False
#range starts with 3 and only needs to go up to the square root of n
#for all odd numbers
for x in range (3, int(n**0.5)+1, 2):
if n % x == 0:
return False
return True #if it makes it through all the catches, it is a prime
This took me about 5 secs to get the answer.
import math
def is_prime_number(x):
for i in range(int(math.sqrt(x)), 2, -1):
if x % i == 0:
return False
return True
def next_prime_number(number):
#Returns the next prime number.
if number % 2 == 0 and number != 2:
number += 1
while not is_prime_number(number):
number += 2
return number
num = 600851475143
i = 2
while (i < long(math.sqrt(num) / 2)):
if num % i == 0:
largest = i
print largest
i = next_prime_number(i + 1)
xrange won't probably help you(or it may!),but the key thing here is to reliaze that you don't need to find the prime numbers up till 600851475143 or the factors of 600851475143,but it's prime factors,so...
Use the good old prime factorization method ,like so:
A=600851475143
n=2
fac=[]
while(n<=int(A)):
B=1
while(A%n==0):
B=0
A=A/n
if(B==0):
fac.append(n)
n=n+1
print max(fac)
This will return the argest prime factor almost instantly
I was battling with this Python "OverflowError", as well, working on this project. It was driving me nuts trying to come up with a combination that worked.
However, I did discover a clever, at least I think so :), way to do it.
Here is my code for this problem.
def IsNumberPrime(n):
bounds = int(math.sqrt(n))
for number in xrange(2,bounds+2):
if n % number == 0:
return False
return True
def GetListOfPrimeFactors(n):
primes = []
factors = GetListOfFactors(n)
if n % 2 == 0:
primes.append(2)
for entries in factors:
if IsNumberPrime(entries):
primes.append(entries)
return primes
GetListOfPrimeFactors(600851475143)
def GetListOfFactors(n):
factors = []
bounds = int(math.sqrt(n))
startNo = 2
while startNo <= bounds:
if n % startNo == 0:
factors.append(startNo)
startNo += 1
return factors
What I did was take the factors of the number entered and enter them into a list "factors". After that, I take the list of factors and determine which ones are primes and store them into a list, which is printed.
I hope this helps
-- Mike

Python prime number list wrong?

I've tried with several different methods to get the 10001 prime number.
def isPrime(value):
if ((2**value)-2)%value==0:
return True
def nthPrime(n):
count = 0
value = 1
while count < n:
value += 1
if isPrime(value):
count += 1
return value
When 10001 is the argument this returns 103903. When I'm expecting 104743.
I've tried:
primes = []
for i in range(2,105000):
if ((2**i) - 2) % i == 0:
primes.append(i)
print primes[10001] ---> 103903
I believe your prime sieve is wrong. Try using an isPrime function that takes that number mod each lesser prime. If any of these are 0 then the number is composite (not prime). To the best of my knowledge there is no single comparison that will tell you if a number is prime, as your isPrime function assumes.
Is this for Project Euler? It does seem familiar to me.
Your isPrime function is wrong, like TEOUltimus said, there is no one way to tell if a number is prime.
Simple Prime Generator in Python
This pretty much answers your question i guess.
You can make a function to generate primes, this might be slow but it will work.
Here's my function to do so :
def PrimesSieve(limit):
np=set()
p=[2]
for i in xrange(1,limit+1,2):
if i == 1: continue
if {i} & np: continue
beg=2 if i % 2 == 0 else 0
for j in xrange(beg,int(limit)+1,i):
np.add(j)
p.append(i)
return p

Categories

Resources