What is the logic of this process - python

I was working on a problem in Project Euler; and I found a question in SO. The question and accepted answer says;
n = 600851475143
i = 2
while i * i < n:
while n%i == 0:
n = n / i
i = i + 1
print (n)
It's just awesome. I still can't understand how this process is so fast and can find the largest prime factor of 600billion in 0.00001 seconds. I tried tons of methods and codes for that, processes took over than 1 hour..
Could anyone explain me the logic of this codes and why it's super-fast? is while loop have a special place in Python?

The fundamental theorem of arithmetic states that every integer greater than 1 can be represented as the product of prime numbers. E.g., the number 2100 can be represented like so:
2 x 2 x 3 x 5 x 5 x 7
I've arranged it so the largest prime factor is on the right, in this case 7. What this algorithm is doing is starting from 2 and dividing n (i.e. "removing" that factor) until there are no more to remove (the modulo 0 step checks that it is divisible cleanly before dividing.)
So, following the code, we would have i = 2 and n = 2100, or
2 x 2 x 3 x 5 x 5 x 7
2100 is divisible by 2 (2100 % 2 == 0) and also because we see a 2 in the factorization above. So divide it by 2 and we get 1050, or
2 x 3 x 5 x 5 x 7
Continue dividing by 2, once more, and you get a number that is no longer divisible by 2, that is 525, or
3 x 5 x 5 x 7
Then we increase i to 3 and continue. See how by the end we will be left with the highest prime factor?
The reason for the first while loop's i * i < n (which really should be i * i <= n) is because
if one divisor or factor of a number (other than a perfect square) is greater than its square root, then the other factor will be less than its square root. Hence all multiples of primes greater than the square root of n need not be considered.
from: http://britton.disted.camosun.bc.ca/jberatosthenes.htm
So if i is greater than the square root of n, that means all remaining factors would have had a "pair" that we already found, below the square root of n. The check used, i * i <= n is equivalent but faster than doing a square root calculation.
The reason this is so quick and other brute force methods are so slow is because this is dividing the number down in each step, which exponentially cuts the number of steps that need to be done.
To see this, the prime factorization of 600851475143 is
71 x 839 x 1471 x 6857
and if you modify the code to read:
n = 600851475143
i = 2
while i * i <= n:
while n%i == 0:
print "Dividing by %d" % i
n = n / i
i = i + 1
if n > 1:
print n
You'll see:
>>>
Dividing by 71
Dividing by 839
Dividing by 1471
6857
which shows you that this is exactly how it's working.

Related

Run time optimisation Prime or Not

I was tasked to write a program that takes in an input as an integer. If the number is prime the program returns 1 and if the number is not prime the program returns the smallest divisor greater than 1.
def isPrime(n):
if n > 1:
for i in range (2,n):
if (n % i) == 0 :
return i
return 1
I'm trying to improve the run time of this code can i get some help please?
Using the same algorithm, one step you can take to improve the runtime is by optimizing your for loop so that it only checks to the square root of n:
def isPrime(n):
if n > 1:
for i in range (2,int(n ** .5) + 1):
if (n % i) == 0 :
return i
return 1
This will reduce the runtime of your algorithm from O(n) to O(sqrt(n))
Okay, since you asked for an explanation on why we should only check to the square root of n:
Let's say we have a number, 36. The factors of 36 are: 1,2,3,4,6,9,12,18,36
In any case, if the factors of 36 are a and b, so that a * b = 36 and a < b, this inequality will ALWAYS hold true:
a <= sqrt(36) <= b
This means that, if there are no factors of 36 from 2 all the way to the square root of n, no factors will exist that are greater than the square root of n.
The reason we check the square root as well is for numbers like 49, who have no factors other than its square root, 7. This is why we add 1 to the int(n ** .5), because the conversion will round it down, which makes it not inclusive in the for loop.

How to find even sum

I need to find the sum of all even numbers below the inserted number. For example if I insert 8 then the sum would be 2+4+6+8=20. If I insert 9 then it also needs to be 20. And it needs to be based on recursion.
This is what I have so far:
def even(a):
if a == 0:
else:
even(a - 1)
even(8)
I cannot figure out what to change under the "if" part for it to give the right outcome
If the function is called with an odd number, n, then you can immediately call again with the number below (an even).
Then if the function is called with an even number return that even number plus the result of summing all the even numbers below this number by calling again with n - 2.
Finally, your base case occurs when n = 0. In this case just return 0.
So we have
def even_sum(n):
if n % 2 == 1: # n is odd
return even_sum(n - 1)
if n == 0:
return 0
return n + even_sum(n - 2)
which works as expected
>>> even_sum(8)
20
>>> even_sum(9)
20
>>> even_sum(0)
0
To design a recursive algorithm, the first thing to wonder is "In what cases can my algorithm return an answer trivially?". In your case, the answer is "If it is called with 0, the algorithm answers 0". Hence, you can write:
def even(n):
if n == 0:
return 0
Now the next question is "Given a particular input, how can I reduce the size of this input, so that it will eventually reach the trivial condition?"
If you have an even number, you want to have this even number + the sum of even numbers below it, which is the result of even(n-2). If you have an odd number, you want to return the sum of even numbers below it. Hence the final version of your function is:
def even(n):
if n == 0 or n == 1:
return 0
if n % 2 == 0:
return n + even(n - 2)
return even(n - 1)
Both with o(n) time complexity
With For loop
num = int(input("Enter a number: ")) # given number to find sum
my_sum = 0
for n in range(num + 1):
if n % 2 == 0:
my_sum += n
print(my_sum)
With recursion
def my_sum(num):
if num == 0:
return 0
if num % 2 == 1:
return my_sum(num - 1)
return num + my_sum(num - 2)
always avoid O(n^2) and greater time complexity
For a recursive solution:
def evenSum(N): return 0 if N < 2 else N - N%2 + evenSum(N-2)
If you were always given an even number as input, you could simply recurse using N + f(N-2).
For example: 8 + ( 6 + (4 + ( 2 + 0 ) ) )
But the odd numbers will require that you strip the odd bit in the calculation (e.g. subtracting 1 at each recursion)
For example: 9-1 + ( 7-1 + ( 5-1 + ( 3-1 + 0 ) ) )
You can achieve this stripping of odd bits by subtracting the modulo 2 of the input value. This subtracts zero for even numbers and one for odd numbers.
adjusting your code
Your approach is recursing by 1, so it will go through both the even and odd numbers down to zero (at which point it must stop recursing and simply return zero).
Here's how you can adjust it:
Return a value of zero when you are given zero as input
Make sure to return the computed value that comes from the next level of recursion (you are missing return in front of your call to even(a-1)
Add the parameter value when it is even but don't add it when it is odd
...
def even(a):
if a == 0 : return 0 # base case, no further recusion
if a%2 == 1 : return even(a-1) # odd number: skip to even number
return a + even(a-1) # even number: add with recursion
# a+even(a-2) would be better
A trick to create a recursive function
An easy way to come up with the structure of a recursive function is to be very optimistic and imagine that you already have one that works. Then determine how you would use the result of that imaginary function to produce the next result. That will be the recursive part of the function.
Finally, find a case where you would know the answer without using the function. That will be your exit condition.
In this case (sum of even numbers), imagine you already have a function magic(x) that gives you the answer for x. How would you use it to find a solution for n given the result of magic(n-1) ?
If n is even, add it to magic(n-1). If n is odd, use magic(n-1) directly.
Now, to find a smaller n where we know the answer without using magic(). Well if n is less than 2 (or zero) we know that magic(n) will return zero so we can give that result without calling it.
So our recursion is "n+magic(n-1) if n is even, else magic(n-1)"
and our stop condition is "zero if n < 2"
Now substitute magic with the name of your function and the magic is done.
For an O(1) solution:
Given that the sum of numbers from 1 to N can be calculated with N*(N+1)//2, you can get half of the sum of even numbers if you use N//2 in the formula. Then multiply the result by 2 to obtain the sum of even numbers.
so (N//2)*(N//2+1) will give the answer directly in O(1) time:
N = 8
print((N//2)*(N//2+1))
# 20
# other examples:
for N in range(10):
print(N,N//2*(N//2+1))
# 0 0
# 1 0
# 2 2
# 3 2
# 4 6
# 5 6
# 6 12
# 7 12
# 8 20
# 9 20
Visually, you can see the progression like this:
1..n : 1 2 3 4 5 6 7 8
∑n : 1 3 6 10 15 21 28 36 n(n+1)/2
n/2 : 0 1 1 2 2 3 3 4
1..n/2 : 1 2 3 4
∑n/2 : 1 3 5 10 half of the result
2∑n/2 : 2 6 10 20 sum of even numbers
So we simply replace N with N//2 in the formula and multiply the result by 2:
N*(N+1)//2 --> replace N with N//2 --> N//2*(N//2+1)//2
N//2*(N//2+1)//2 --> multiply by 2 --> N//2*(N//2+1)
Another way to see it is using Gauss's visualisation of the sum of numbers but using even numbers:
ascending 2 4 6 8 ... N-6 N-4 N-2 N (where N is even)
descending N N-2 N-4 N-6 ... 8 6 4 2
--- --- --- --- --- --- --- ---
totals N+2 N+2 N+2 N+2 ... N+2 N+2 N+2 N+2 (N/2 times N+2)
Because we added the even numbers twice, once in ascending order and once in descending order, the sum of all the totals will be twice the sum of even numbers (we need to divide that sum by 2 to get what we are looking for).
sum of evens: N/2*(N+2)/2 --> N/2*(N/2+1)
The N/2(N/2+1) formulation allows us to supply the formula with an odd number and get the right result by using integer division which absorbs the 'odd bit': N//2(N//2+1)
Recursive O(1) solution
Instead of using the integer division to absorb the odd bit, you could use recursion with the polynomial form of N/2*(N+2)/2: N^2/4 + N/2
def sumEven(n):
if n%2 == 0 : return n**2/4 + n/2 # exit condition
return sumEven(n-1) # recursion
Technically this is recursive although in practice it will never go deeper than 1 level
Try out this.
>>> n = 5
>>> sum(range(0, n+1, 2))
with minimum complexity
# include <stdio.h>
void main()
{
int num, sum, i;
printf("Number: ");
scanf("%d", &num);
i = num;
if (num % 2 != 0)
num = num -1;
sum = (num * (num + 2)) / 4;
printf("The sum of even numbers upto %d is %d\n\n", i, sum);
}
It is a C program and could be used in any language with respective syntax.
And it needs to be based on recursion.
Though you want a recursion one, I still want to share this dp solution with detailed steps to solve this problem.
Dynamic Programming
dp[i] represents the even sum among [0, i] which I denote as nums.
Case1: When i is 0, there is one number 0 in nums. dp[0] is 0.
Case2: When i is 1, there are two numbers 0 and 1 in nums. dp[1] is still 0.
Case3: When i is 2, there are three numbers 0, 1 and 2 in nums. dp[2] is 2.
Case4: When i is greater than 2, there are two more cases
If i is odd, dp[i] = dp[i-1]. Since i is odd, it is the same with [0, i-1].
If i is even, dp[i] = dp[i-2] + i by adding the current even number to the even sum among [0, i-2] (i-1 is odd, so won't be added).
PS. dp[i] = dp[i-1] + i is also ok. The difference is how you initialize dp.
Since we want the even sum among [0, n], we return dp[n]. You can conclude this from the first three cases.
def even_sum(n):
dp = []
# Init
dp.append(0) # dp[0] = 0
dp.append(0) # dp[1] = 0
# DP
for i in range(2, n+1): # n+1 because range(i, j) results [i, j) and you take n into account
if i % 2 == 1: # n is odd
dp.append(dp[i-1]) # dp[i] = dp[i-1]
else: # n is even
dp.append(dp[i-2] + i) # dp[i] = dp[i-2] + i
return dp[-1]

Implement the recursion in pythonic way

I have a recursion:
C(n) = min{
C(n/3) + 1 if n ⋮ 3,
C(n/2) + 1 if n ⋮ 2,
C(n-1) + 1
}
base case being
C(n) = 0 for n <= 1
How can I implement this recursion in a pythonic way?
This is an attempt to solve the given problem which I was able to solve successfully but I feel the need to implement a recursive solution also.
Problem 1: Primitive Calculator
You are given a primitive calculator that can perform the following three operations with the current number x: multiply x by 2, multiply x by 3, or add 1 to x. Your goal is given a positive integer n, find the minimum number of operations needed to obtain the number n starting from the number 1.
Problem Description
Task. Given an integer n, compute the minimum number of operations needed to obtain the number n starting from the number 1.
Output Format. In the first line, output the minimum number k of operations needed to get n from 1. In the second line output a sequence of intermediate numbers. That is, the second line should contain positive integers a0, a2,…, a(k-1) such that a0 =1, a(k-1) =n and for all 0≤i<k-1, ai+1 is equal to either ai + 1, 2 x ai, or 3 x ai. If there are many such sequences, output any one of them.
Sample 1.
Input: 5
Output:
3
1 2 4 5
Explanation:
Here, we first multiply 1 by 2 two times and then add 1 ( ((1 x 2) x 2) + 1). Another possibility is to first multiply by 3 and then add 1 two times. Hence “1 3 4 5” is also a valid output in this case.
Sample 2:
Input: 96234
Output:
14
1 3 9 10 11 22 66 198 594 1782 5346 16038 16039 32078 96234
Explanation:
Again, another valid output in this case is “1 3 9 10 11 33 99 297 891 2673 8019 16038 16039 48117 96234”.
Your goal is to design and implement a dynamic programming solution for this problem. A natural subproblem in this case is the following: C(n) is the minimum number of operations required to obtain n from 1 (using the three primitive operations). How to express C(n) through C(n/3), C(n/2), C(n-1)?
def C(n):
if n <= 1:
return 0
m= C(n-1)
if n % 3 == 0:
m= min(m, C(n/3))
if n % 2 == 0:
m= min(m, C(n/2))
return m + 1
It might be worth to consider memoization.
Cache= {}
def C(n):
global Cache
if n <= 1:
return 0
try:
return Cache[n]
except:
m= C(n-1)
if n % 3 == 0:
m= min(m, C(n/3))
if n % 2 == 0:
m= min(m, C(n/2))
m+= 1
Cache[n]= m
return m
I am unsure whether it is better to test for n <= 1 first.

Finding the smallest positive number that is evenly divisible by all of the numbers from 1 to 20? [duplicate]

This question already has answers here:
Least common multiple for 3 or more numbers
(32 answers)
Closed 5 years ago.
This is a Project Euler challenge where I'm trying to find the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
The logic while I came up with seems to run really slowly. It's been running for the last 4 mins and still hasn't found the number. I'm trying to figure out a) Is this logic correct? b) Why does this take so long? and c) Could someone give me a hint on an alternate logic that is more efficient.
# 2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.
# What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
smallest_num = 2520
while smallest_num >= 2520:
divisor = 2
while smallest_num % divisor == 0 and divisor < 21:
print("Smalles num = {} and Divisor = {}").format(smallest_num, divisor)
divisor += 1
smallest_num += 1
print("Smallest number is: {}").format(smallest_num)
This is still processing and so far my terminal looks like this
Here's your method run "properly" (using the term liberally), but as #James mentioned it will take an egregious amount of time as a loop.
divisors = np.arange(1, 21)
num = 2520
while True:
if np.all(num % divisors == 0):
print(num)
break
num += 1
A much better method (for Python 3.x). Directly from a similar question:
import functools
import math
functools.reduce(lambda x,y: x*y//math.gcd(x, y), range(1, 21))
Out[27]: 232792560
The following code works fine.
#!/usr/bin/env python
import math
#Generating primes
divisorMax = 20;
top = divisorMax + 1 #divisor max is the upper limit
p = [x for x in range(2,top)]
for num in p:
for idx in range(2,(top//num)+1):
if num*idx in p:
p.remove(num*idx)
#Solving the problem
result = 1;
for i in range(0, len(p)):
a = math.floor(math.log(divisorMax) / math.log(p[i]));
result = result * (p[i]**a);
print(result)
You are using brute force technique to calculate the number, which is easy to understand and write, but takes very much time.
I am using the Prime Factorisation technique explained here.
i am not 100% sure, if my solution is really correct, but i guess it is and it is pretty fast.
First of all, we don't need to care for all divisors, as most are multiples of each other. So best way is to count the divisors backwards, for example starting with 20 down to 1.
I had a look at the prime numbers, the solution needs to be a multiple of all primes above 10, furthermore we need to check the 20 divisor, the rest can be ignored, as when testing divisor 18, the 9 will work as well, and so on.
So i mulitplied 11 * 13 * 17 * 19 * 20. The resulting is 923780 and is divisible by at least the primes + 20.
So i would start at 923780 and test only every 923780th number.
smallest_num = 923780
steps = 923780
while True:
divisor = 19
while smallest_num % divisor == 0 and divisor > 10:
print("Smalles num = {} and Divisor = {}").format(smallest_num, divisor)
divisor -= 1
if divisor == 10:
print("Smallest number is: {}").format(smallest_num)
break
smallest_num += steps
Maybe i have logical error?!

Stuck on Project Euler #3 in python

The prime factors of 13195 are 5, 7, 13 and 29. What is the largest
prime factor of the number 600851475143 ?
Ok, so i am working on project euler problem 3 in python. I am kind of confused. I can't tell if the answers that i am getting with this program are correct or not. If somone could please tell me what im doing wrong it would be great!
#import pdb
odd_list=[]
prime_list=[2] #Begin with zero so that we can pop later without errors.
#Define a function that finds all the odd numbers in the range of a number
def oddNumbers(x):
x+=1 #add one to the number because range does not include it
for i in range(x):
if i%2!=0: #If it cannot be evenly divided by two it is eliminated
odd_list.append(i) #Add it too the list
return odd_list
def findPrimes(number_to_test, list_of_odd_numbers_in_tested_number): # Pass in the prime number to test
for i in list_of_odd_numbers_in_tested_number:
if number_to_test % i==0:
prime_list.append(i)
number_to_test=number_to_test / i
#prime_list.append(i)
#prime_list.pop(-2) #remove the old number so that we only have the biggest
if prime_list==[1]:
print "This has no prime factors other than 1"
else:
print prime_list
return prime_list
#pdb.set_trace()
number_to_test=raw_input("What number would you like to find the greatest prime of?\n:")
#Convert the input to an integer
number_to_test=int(number_to_test)
#Pass the number to the oddnumbers function
odds=oddNumbers(number_to_test)
#Pass the return of the oddnumbers function to the findPrimes function
findPrimes(number_to_test , odds)
The simple solution is trial division. Let's work through the factorization of 13195, then you can apply that method to the larger number that interests you.
Start with a trial divisor of 2; 13195 divided by 2 leaves a remainder of 1, so 2 does not divide 13195, and we can go on to the next trial divisor. Next we try 3, but that leaves a remainder of 1; then we try 4, but that leaves a remainder of 3. The next trial divisor is 5, and that does divide 13195, so we output 5 as a factor of 13195, reduce the original number to 2639 = 13195 / 5, and try 5 again. Now 2639 divided by 5 leaves a remainder of 4, so we advance to 6, which leaves a remainder of 5, then we advance to 7, which does divide 2639, so we output 7 as a factor of 2639 (and also a factor of 13195) and reduce the original number again to 377 = 2639 / 7. Now we try 7 again, but it fails to divide 377, as does 8, and 9, and 10, and 11, and 12, but 13 divides 2639. So we output 13 as a divisor of 377 (and of 2639 and 13195) and reduce the original number again to 29 = 377 / 13. As this point we are finished, because the square of the trial divisor, which is still 13, is greater than the remaining number, 29, which proves that 29 is prime; that is so because if n=pq, then either p or q must be less than, or equal to the square root of n, and since we have tried all those divisors, the remaining number, 29, must be prime. Thus, 13195 = 5 * 7 * 13 * 29.
Here's a pseudocode description of the algorithm:
function factors(n)
f = 2
while f * f <= n
if f divides n
output f
n = n / f
else
f = f + 1
output n
There are better ways to factor integers. But this method is sufficient for Project Euler #3, and for many other factorization projects as well. If you want to learn more about prime numbers and factorization, I modestly recommend the essay Programming with Prime Numbers at my blog, which among other things has a python implementation of the algorithm described above.
the number 600851475143 is big to discourage you to use brute-force.
the oddNumbers function in going to put 600851475143 / 2 numbers in odd_list, that's a lot of memory.
checking that a number can be divided by an odd number does not mean the odd number is a prime number. the algorithm you provided is wrong.
there are a lot of mathematical/algorithm tricks about prime numbers, you should and search them online then sieve through the answers. you might also get to the root of the problem to make sure you have squared away some of the issues.
you could use a generator to get the list of odds (not that it will help you):
odd_list = xrange(1, number+1, 2)
here are the concepts needed to deal with prime numbers:
http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
http://en.wikipedia.org/wiki/Primality_test
if you are really stuck, then there are solutions already there:
Project Euler #3, infinite loop on factorization
Project Euler 3 - Why does this method work?
Project Euler Question 3 Help
Here is my Python code:
num=600851475143
i=2 # Smallest prime factor
for k in range(0,num):
if i >= num: # Prime factor of the number should not be greater than the number
break
elif num % i == 0: # Check if the number is evenly divisible by i
num = num / i
else:
i= i + 1
print ("biggest prime number is: "+str(num))
'''
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?
'''
import math
def isPrime(x):
if x<2:
return False
for i in range(2,int(math.sqrt(x))):
if not x%i:
return False
return True
def largest_factor(number):
for i in range (2, int(math.sqrt(number))):
if number%i == 0:
number = number/i
if isPrime(number) is True:
max_val = number
break
print max_val
else:
i += 1
return max_val
largest_factor(600851475143)
This actually compiles very fast. It checks for the number formed for being the prime number or not.
Thanks
Another solution to this problem using Python.
def lpf(x):
lpf=2
while (x>lpf):
if (x%lpf==0):
x=x/lpf
else:
lpf+=1
return x
print(lpf(600851475143))
i = 3
factor = []
number = 600851475143
while i * i <= number:
if number % i != 0:
i += 2
else:
number /= i
factor.append(i)
while number >= i:
if number % i != 0:
i += 2
else:
number /= i
factor.append(i)
print(max(factor))
Here is my python code
a=2
list1=[]
while a<=13195: #replace 13195 with your input number
if 13195 %a ==0: #replace 13195 with your input number
x , count = 2, 0
while x <=a:
if a%x ==0:
count+=1
x+=1
if count <2:
list1.append(a)
a+=1
print (max(list1))
Here is my python code:
import math
ma = 600851475143
mn = 2
s = []
while mn < math.sqrt(ma):
rez = ma / mn
mn += 1
if ma % mn == 0:
s.append(mn)
print(max(s))
def prime_max(x):
a = x
i = 2
while i in range(2,int(a+1)):
if a%i == 0:
a = a/i
if a == 1:
print(i)
i = i-1
i = i+1

Categories

Resources