I am experiencing some running time issues with Project Euler. The exercise can be found here:
Project Euler exercise 12. My solution is:
def triangularnr(n):
T_n = n*(n+1)/2 #Function to calculate triangular numbers
return T_n
for n in range(1,1*10**8): #Nr with over 500 divisors is large, large range required
count = 2 #Every nr is divisible by itself and by 1, thus initially count = 2
for i in range(2,int(triangularnr(n))): #Defining i to find divisors
if triangularnr(n)%i == 0:
count+=1 #Incrementing count to count the nr of divisors
if count > 500: #If a triangularnr has over 500 divisors we want to print the nr
print(triangularnr(n))
break
I've tried to optimize the code by reducing the nr of steps required and by using a mathematical formula for triangular numbers. My code works for 5 divisors, but it takes ages to find 500 divisors. I've let the code run for 3 hours yesterday and still no output. Should I let the code run for more than 3 hours, or will the output never be printed as there is something wrong with my code?
This is more a mathematical answer than a programming one, but one way to improve your algorithm is to think about how to determine the number of divisors of a number.
The brute force way would be to iterate over all numbers smaller than your test number and check every one of them but this is not very efficient for large numbers as you found out.
A more efficient way would be to consider the prime decomposition of your test number. Any integer can be written as the product of prime numbers. Suppose that N has prime factors p1, p2,... , pn with exponents k1, k2,... ,kn, i.e. N == p1**k1 * p2**k2 * ... * pn**kn, then the number of divisors of N is equal to (k1+1)*(k2+1)*...*(kn+1). So finding the number of divisors is equivalent to finding the prime factors of a number which restricts the number of integers you need to check considerably.
Another thing to realize is that if integers N1 and N2 have no prime factors in common (which is the case for N and N+1), the number of divisors of N1*N2 is equal to the number of divisors of N1 times the number of divisors of N2. This means that since you are considering numbers of the form N*(N+1)//2 and since N and N+1 have no prime factors in common, the number of divisors of your triangular numbers is equal to the product of the number of divisors of N//2 and the number of divisors of N+1 for even N, and to the product of the number of divisors of N and the number of divisors of (N+1)//2 for odd N.
Firstly, as a rule of thumb, for most project Euler exercises your code should take less than a minute to run. Remember, questions on project Euler challenge your ability to come up with interesting solutions, not to brute force answers.
Your algorithm is inefficient because:
Triangular numbers increase by the square (expand n*(n+1)/2)
Your algorithm loops through every triangular number
These two things mean that your algorithm probably has a complexity of n^3. Eg. doubling the required number of factors increases the search space by a factor of 8.
One tip that might prove useful is that if you have two numbers, a and b, the number of factors of a*b is equal to the number of factors of a multiplied by the number of factors of b. For example 5 has two factors (5, 1) and 14 has 4 factors (1, 2 ,7 and 14). From this we know that 5*14 has 2*4 factors, without having to search the numbers from 1 to 70.
Lucky for you the triangular number formula T_n = n * (n + 1) / 2 already comes broken down into two factors, so you need to code something to:
Determine if n or n + 1 is even
Divide the even factor by 2
Calculate the number of factors of these factors
Multiply these numbers to find the number of factors of the triangular number
Hope that helped :)
Related
I have a Python Code to get the largest prime factor of a Number and the below is my code
When I give the input to the number up to an 8-digit number takes a few minutes but when I tried running the code for a 12-digit number 600851475143 it took more time and still it didn't give any output or any error.
So is there any way how to get the output for the 12-digit numbers quickly?
def large_prime_fact(num):
prime_factors=[]
if num==2 or num==3:
return(prime_factors.append(num))
if num%2==0:
prime_factors.append(2)
for i in range(3,num,2):
cnt=0
if num%i==0:
for j in range(2,i):
if i%j==0:
cnt+=1
if cnt==0 and i!=2:
prime_factors.append(i)
return prime_factors
if __name__=='__main__':
number=int(input('Enter the number:'))
print('The Largest prime factor for',number,'is :',max(large_prime_fact(number)))
As Karl Knechtel pointed out your approach is seriously flawed. Here on SO there are lots of questions about prime numbers and factorization, which you may want to read.
That said, here's my solution. It may still benefit from further optimizations, but it solves your 600851475143 example in about 1ms.
##define a prime numbers generator
def prime_gen():
primes = []
n = 2
while n < 2**64:
if primes == []:
primes.append(n)
yield n
elif len(primes) == 1:
n = 3
primes.append(n)
yield n
else:
n += 2
limit = int(sqrt(n))+1
for p in takewhile(lambda x:x<limit, primes):
if n%p==0:
break
else:
primes.append(n)
yield n
##factorize and return largest factor
def largest_prime(n):
target = n
for x in prime_gen():
while target % x == 0:
target //= x
if target == 1:
return x
You have two algorithms here:
An algorithm for finding all factors of num, which contains
An algorithm for checking the primality of each factor you find
Both algorithms are implemented incredibly inefficiently. The primality tester knows, from the moment it finds a single smaller value which divides it, that it's not prime, but you continue counting all the factors of that number, and use the count solely to check if it's zero or non-zero. Since the vast majority of composite numbers will have a smallish factor, you could just break your checking loop as soon as you find even one, knowing it's composite immediately and avoiding huge amounts of work.
Even better, you could pre-compute the prime numbers up to the square root of the target number (note: Only need to go up to the square root because any factor larger than the square root definitionally has a factor below the square root which you could use to find it without exhaustive search). Efficiently computing all prime numbers in a fixed range (especially such a tiny range as the square root of your target number, which is under 1M) can be done much more efficiently than repeated trial division (search information on the Sieve of Eratosthenes for a decent algorithm for smallish primes).
Replacing slow per factor primality tests from #2 with a cheap precompute of all possible prime factors below the square root (allowing you to cheaply determine any prime factors above the square root) should solve the problem. There are additional optimizations available, but that should get 99% of it.
I saw this YouTube video online where this guy finds the largest prime factor of a number using a seemingly simple approach, but I don't quite understand the math of it. Here's the link https://m.youtube.com/watch?v=5kv9q7qgvlI
The code -
n=1234 # Some number whose largest factor I want to find
i=2 # It seems that he tries to start from the smallest prime number
while i**2<n: # I don't understand this part where he checks if the square of variable is less than the target number
while n%i==0: # I know this checks if n is divisible by i
n/=i
i+=1 # increments i's value
print(n)
I know that this code works, but why? I get the last two lines, but why is it necessary to check if the square of variable i is less than n?
If your number N is divisible by I (in other terms, I being a factor of N), and I is greater than sqrt(N), then there must be another factor of N, call it J = N/I, being smaller than sqrt(N).
If you exhaustively searched all potential factors up to I, you must have already found J, so you covered that factorization earlier.
We are looking for the largest prime factor, so the question remains whether the final N when terminating the loop is a prime number.
Whenever we encountered a factor of N, we divided N by this factor, so when considering a potential factor I, we can be sure that the current N won't have any factors below I any more.
Can the final N when terminating the loop be composed from more than one factor (i.e. not being prime)?
No.
If N isn't prime, it must be composed from K and L (N = K * L), and K and L must be both bigger than sqrt(N), otherwise we would have divided by K or L in an earlier step. But multiplying two numbers, each bigger than sqrt(N), will always be bigger than N, violating N = K * L.
So, assuming that the final N wasn't prime, runs into a contradiction, and thus we can be sure that the final N is a factor of the original N, and that this factor is indeed a prime number.
Caveats with the original code (thanks JohanC):
The original code checks for I being strictly less than SQRT(N) (while i**2<n). That will miss cases like N=9 where its square root 3 must be included in the iteration. So, this should better read while i**2<=n.
And the code risks some inaccuracies:
Using floating-point division (/= operator instead of //=) might give inexact results. This applies to Python, while in languages like Java, /= would be fine.
In Python, raising an integer to the power of 2 (while i**2<=n) seems to guarantee exact integer arithmetic, so that's ok in the Python context. In languages like Java, I'd recommend not to use the pow() function, as that typically uses floating-point arithmetic with the risk of inexact results, but to simply write i*i.
The problem is:
Given a range of numbers (x,y) , Find all the prime numbers(Count only) which are sum of the squares of two numbers, with the restriction that 0<=x<y<=2*(10^8)
According to Fermat's theorem :
Fermat's theorem on sums of two squares asserts that an odd prime number p can be
expressed as p = x^2 + y^2 with integer x and y if and only if p is congruent to
1 (mod4).
I have done something like this:
import math
def is_prime(n):
if n % 2 == 0 and n > 2:
return False
return all(n % i for i in range(3, int(math.sqrt(n)) + 1, 2))
a,b=map(int,raw_input().split())
count=0
for i in range(a,b+1):
if(is_prime(i) and (i-1)%4==0):
count+=1
print(count)
But this increases the time complexity and memory limit in some cases.
Here is my submission result:
Can anyone help me reduce the Time Complexity and Memory limit with better algorithm?
Problem Link(Not an ongoing contest FYI)
Do not check whether each number is prime. Precompute all the prime numbers in the range, using Sieve of Eratosthenes. This will greatly reduce the complexity.
Since you have maximum of 200M numbers and 256Mb memory limit and need at least 4 bytes per number, you need a little hack. Do not initialize the sieve with all numbers up to y, but only with numbers that are not divisible by 2, 3 and 5. That will reduce the initial size of the sieve enough to fit into the memory limit.
UPD As correctly pointed out by Will Ness in comments, sieve contains only flags, not numbers, thus it requires not more than 1 byte per element and you don't even need this precomputing hack.
You can reduce your memory usage by changing for i in range(a,b+1): to for i in xrange(a,b+1):, so that you are not generating an entire list in memory.
You can do the same thing inside the statement below, but you are right that it does not help with time.
return all(n % i for i in xrange(3, int(math.sqrt(n)) + 1, 2))
One time optimization that might not cost as much in terms of memory as the other answer is to use Fermat's Little Theorem. It may help you reject many candidates early.
More specifically, you could pick maybe 3 or 4 random values to test and if one of them rejects, then you can reject. Otherwise you can do the test you are currently doing.
First of all, although it will not change the order of your time-complexity, you can still narrow down the list of numbers that you are checking by a factor of 6, since you only need to check numbers that are either equal to 1 mod 12 or equal to 5 mod 12 (such as [1,5], [13,17], [25,29], [37,41], etc).
Since you only need to count the primes which are sum of squares of two numbers, the order doesn't matter. Therefore, you can change range(a,b+1) to range(1,b+1,12)+range(5,b+1,12).
Obviously, you can then remove the if n % 2 == 0 and n > 2 condition in function is_prime, and in addition, change the if is_prime(i) and (i-1)%4 == 0 condition to if is_prime(i).
And finally, you can check the primality of each number by dividing it only with numbers that are adjacent to multiples of 6 (such as [5,7], [11,13], [17,19], [23,25], etc).
So you can change this:
range(3,int(math.sqrt(n))+1,2)
To this:
range(5,math.sqrt(n))+1,6)+range(7,math.sqrt(n))+1,6)
And you might as well calculate math.sqrt(n))+1 beforehand.
To summarize all this, here is how you can improve the overall performance of your program:
import math
def is_prime(n):
max = int(math.sqrt(n))+1
return all(n % i for i in range(5,max,6)+range(7,max,6))
count = 0
b = int(raw_input())
for i in range(1,b+1,12)+range(5,b+1,12):
if is_prime(i):
count += 1
print count
Please note that 1 is typically not regarded as prime, so you might want to print count-1 instead. On the other hand, 2 is not equal to 1 mod 4, yet it is the sum of two squares, so you may leave it as is...
The following below is an algorithm that finds the prime factorization for a given number N. I'm wondering if there are any ways to make this faster using HUGE numbers. I'm talking like 20-35 digit numbers. I wanna try and get these to go as fast as possible. Any ideas?
import time
def prime_factors(n):
"""Returns all the prime factors of a positive integer"""
factors = []
divisor = 2
while n > 1:
while n % divisor == 0:
factors.append(divisor)
n /= divisor
divisor = divisor + 1
if divisor*divisor > n:
if n > 1:
factors.append(n)
break
return factors
#HUGE NUMBERS GO IN HERE!
start_time = time.time()
my_factors = prime_factors(15227063669158801)
end_time = time.time()
print my_factors
print "It took ", end_time-start_time, " seconds."
Your algorithm is trial division, which has time complexity O(sqrt(n)). You can improve your algorithm by using only 2 and the odd numbers as trial divisors, or even better by using only prime numbers as trial divisors, but the time complexity will remain O(sqrt(n)).
To go faster you need a better algorithm. Try this:
def factor(n, c):
f = lambda(x): (x*x+c) % n
t, h, d = 2, 2, 1
while d == 1:
t = f(t); h = f(f(h)); d = gcd(t-h, n)
if d == n:
return factor(n, c+1)
return d
To call it on your number, say
print factor(15227063669158801, 1)
That returns the (possibly composite) factor 2090327 virtually instantly. It uses an algorithm called the rho algorithm, invented by John Pollard in 1975. The rho algorithm has time complexity O(sqrt(sqrt(n))), so it's much faster than trial division.
There are many other algorithms for factoring integers. For numbers in the 20 to 35 digit range that interests you, the elliptic curve algorithm is well-suited. It should factor numbers of that size in no more than a few seconds. Another algorithm that is well-suited to such numbers, especially those that are semi-primes (have exactly two prime factors), is SQUFOF.
If you're interested in programming with prime numbers, I modestly recommend this essay on my blog. When you're finished with that, other entries on my blog talk about elliptic curve factorization, and SQUFOF, and various other even more-powerful methods of factoring ever-larger integers.
For example, list all prime factorization for a number 100.
Check 2 is one of factorizations or not. And then, 2 < 2*c <= 100 could be removed. Ex, 4, 6, 8, ... 98
Check 3 is one of factorizations or not. And then, 3 < 2*d <= 100 could be removed. Ex, 9, 12, ... 99
4 is removed from possible set.
Check 5, And then, 10, 15, 20, ..., 100 are removed.
6 is removed.
Check 7, ....
....
It seems like there is no check for divisors. Sorry if I am wrong but how do you know if divisor is prime or not? Your divisor variable is increasing by 1 after each loop so I assume it will generate a lot of composite numbers.
No optimizations to that algorithm will allow you to factor 35 digit numbers at least in the general case. The reason is that the number of primes up to 35 digits are too high to be listed in a reasonable amount of time let alone attempt to divide by each one. Even if one was inclined to try, the number of bits required to store them would be far too much as well. In this case you'll want to select a different algorithm from the list of general purpose factorization algorithms.
However, if all the prime factors are small enough (say below 10^12 or so), then you could use a segmented Sieve of Eratosthenes, or simply find a list of primes up to some practical number (say 10^12 or so) online and use that instead of trying to calculate the primes and hope the list is large enough.
I am trying to solve a problem involving printing the product of all divisors of a given number. The number of test cases is a number 1 <= t <= 300000 , and the number itself can range from 1 <= n <= 500000
I wrote the following code, but it always exceeds the time limit of 2 seconds. Are there any ways to speed up the code ?
from math import sqrt
def divisorsProduct(n):
ProductOfDivisors=1
for i in range(2,int(round(sqrt(n)))+1):
if n%i==0:
ProductOfDivisors*=i
if n/i != i:
ProductOfDivisors*=(n/i)
if ProductOfDivisors <= 9999:
print ProductOfDivisors
else:
result = str(ProductOfDivisors)
print result[len(result)-4:]
T = int(raw_input())
for i in range(1,T+1):
num = int(raw_input())
divisorsProduct(num)
Thank You.
You need to clarify by what you mean by "product of divisors." The code posted in the question doesn't work for any definition yet. This sounds like a homework question. If it is, then perhaps your instructor was expecting you to think outside the code to meet the time goals.
If you mean the product of unique prime divisors, e.g., 72 gives 2*3 = 6, then having a list of primes is the way to go. Just run through the list up to the square root of the number, multiplying present primes into the result. There are not that many, so you could even hard code them into your program.
If you mean the product of all the divisors, prime or not, then it is helpful to think of what the divisors are. You can make serious speed gains over the brute force method suggested in the other answers and yours. I suspect this is what your instructor intended.
If the divisors are ordered in a list, then they occur in pairs that multiply to n -- 1 and n, 2 and n/2, etc. -- except for the case where n is a perfect square, where the square root is a divisor that is not paired with any other.
So the result will be n to the power of half the number of divisors, (regardless of whether or not n is a square).
To compute this, find the prime factorization using your list of primes. That is, find the power of 2 that divides n, then the power of 3, etc. To do this, take out all the 2s, then the 3s, etc.
The number you are taking the factors out of will be getting smaller, so you can do the square root test on the smaller intermediate numbers to see if you need to continue up the list of primes. To gain some speed, test p*p <= m, rather than p <= sqrt(m)
Once you have the prime factorization, it is easy to find the number of divisors. For example, suppose the factorization is 2^i * 3^j * 7^k. Then, since each divisor uses the same prime factors, with exponents less than or equal to those in n including the possibility of 0, the number of divisors is (i+1)(j+1)(k+1).
E.g., 72 = 2^3 * 3^2, so the number of divisors is 4*3 = 12, and their product is 72^6 = 139,314,069,504.
By using math, the algorithm can become much better than O(n). But it is hard to estimate your speed gains ahead of time because of the relatively small size of the n in the input.
You could eliminate the if statement in the loop by only looping to less than the square root, and check for square root integer-ness outside the loop.
It is a rather strange question you pose. I have a hard time imagine a use for it, other than it possibly being an assignment in a course. My first thought was to pre-compute a list of primes and only test against those, but I assume you are quite deliberately counting non-prime factors? I.e., if the number has factors 2 and 3, you are also counting 6.
If you do use a table of pre-computed primes, you would then have to also subsequently include all possible combinations of primes in your result, which gets more complex.
C is really a great language for that sort of thing, because even suboptimal algorithms run really fast.
Okay, I think this is close to the optimal algorithm. It produces the product_of_divisors for each number in range(500000).
import math
def number_of_divisors(maxval=500001):
""" Example: the number of divisors of 12 is 6: 1, 2, 3, 4, 6, 12.
Given a prime factoring of n, the number of divisors of n is the
product of each factor's multiplicity plus one (mpo in my variables).
This function works like the Sieve of Eratosthenes, but marks each
composite n with the multiplicity (plus one) of each prime factor. """
numdivs = [1] * maxval # multiplicative identity
currmpo = [0] * maxval
# standard logic for 2 < p < sqrt(maxval)
for p in range(2, int(math.sqrt(maxval))):
if numdivs[p] == 1: # if p is prime
for exp in range(2,50): # assume maxval < 2^50
pexp = p ** exp
if pexp > maxval:
break
exppo = exp + 1
for comp in range(pexp, maxval, pexp):
currmpo[comp] = exppo
for comp in range(p, maxval, p):
thismpo = currmpo[comp] or 2
numdivs[comp] *= thismpo
currmpo[comp] = 0 # reset currmpo array in place
# abbreviated logic for p > sqrt(maxval)
for p in range(int(math.sqrt(maxval)), maxval):
if numdivs[p] == 1: # if p is prime
for comp in range(p, maxval, p):
numdivs[comp] *= 2
return numdivs
# this initialization times at 7s on my machine
NUMDIV = number_of_divisors()
def product_of_divisors(n):
if NUMDIV[n] % 2 == 0:
# each pair of divisors has product equal to n, for example
# 1*12 * 2*6 * 3*4 = 12**3
return n ** (NUMDIV[n] / 2)
else:
# perfect squares have their square root as an unmatched divisor
return n ** (NUMDIV[n] / 2) * int(math.sqrt(n))
# this loop times at 13s on my machine
for n in range(500000):
a = product_of_divisors(n)
On my very slow machine, it takes 7s to compute the numberofdivisors for each number, then 13s to compute the productofdivisors for each. Of course it can be sped up by translating it into C. (#someone with a fast machine: how long does it take on your machine?)