Why doesn't this code work (Leetcode in Python)? - python

class Solution:
def isHappy(self, n):
list_n, l, ls, num = [n,], 0, 0, 0
while num != 1:
if l != ls:
return False
num = sum([int(i)**2 for i in list(str(n))])
list_n.append(num)
l, ls = len(list_n), len(set(list_n))
return True
Input: 7
Output: False
Expected: True
It's from Happy Number | LeetCode OJ
Write an algorithm to determine if a number is "happy".
A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers.

To answer the question: Your code fails because you're confusing num and n. In particular, you compute num always from n, and neither ever changes. Just get rid of one of them, that will also be less confusing. You really should learn to debug, btw... printing num or n inside the loop would have made it clear what's happening.
Using a set would btw be easier and faster, try that as well. Here's one way:
def isHappy(n):
stop = {1}
while n not in stop:
stop.add(n)
n = sum(int(d)**2 for d in str(n))
return n == 1
And here's one that only uses two single ints. Can you see how it works?
def isHappy(n):
s = lambda n: sum(int(d)**2 for d in str(n))
m = s(n)
while m != n:
n, m = s(n), s(s(m))
return n == 1

The reason is as below:
n has to be reset to newest result after each sum operation. So just add this line before return True :
n=num
And for your reference, here is the working code:
def isHappy(n):
list_n, l, ls, num = [n,], 0, 0, 0
while num != 1:
if l != ls:
return False
num = sum([int(i)**2 for i in list(str(n))])
list_n.append(num)
l, ls = len(list_n), len(set(list_n))
n=num # reset n after each sum calculation
return True

You can keep looping while sm which is the sum of the squares of the digits of the current n or until sm is repeated. Returning sm == 1 to test if the number is happy:
def isHappy( n):
# set initial sum of squares
sm = sum(int(i) * int(i) for i in str(n))
seen = set()
# while we have not hit 1 or we get a repeated `sm`
while sm != 1 and sm not in seen:
# add sm to our set
seen.add(sm)
# update sm
sm = sum(int(i) * int(i) for i in str(sm))
# we will get here either when sm is 1 or we had a repeated sm
return sm == 1
Output:
In [2]: for x in range(100+1):
...: if isHappy(x):
...: print(x)
...:
1
7
10
13
19
23
28
31
32
44
49
68
70
79
82
86
91
94
97
100
As per the wiki page description in your question If n is not happy, then its sequence does not go to 1. Instead, it ends in the cycle so if we see repeated values we know the number is not happy. I don't see anywhere in your code that you are checking that condition.

Related

finding the smallest prime factors of a number using python [duplicate]

Two part question:
Trying to determine the largest prime factor of 600851475143, I found this program online that seems to work. The problem is, I'm having a hard time figuring out how it works exactly, though I understand the basics of what the program is doing. Also, I'd like if you could shed some light on any method you may know of finding prime factors, perhaps without testing every number, and how your method works.
Here's the code that I found online for prime factorization [NOTE: This code is incorrect. See Stefan's answer below for better code.]:
n = 600851475143
i = 2
while i * i < n:
while n % i == 0:
n = n / i
i = i + 1
print(n)
#takes about ~0.01secs
Why is that code so much faster than this code, which is just to test the speed and has no real purpose other than that?
i = 1
while i < 100:
i += 1
#takes about ~3secs
This question was the first link that popped up when I googled "python prime factorization".
As pointed out by #quangpn88, this algorithm is wrong (!) for perfect squares such as n = 4, 9, 16, ... However, #quangpn88's fix does not work either, since it will yield incorrect results if the largest prime factor occurs 3 or more times, e.g., n = 2*2*2 = 8 or n = 2*3*3*3 = 54.
I believe a correct, brute-force algorithm in Python is:
def largest_prime_factor(n):
i = 2
while i * i <= n:
if n % i:
i += 1
else:
n //= i
return n
Don't use this in performance code, but it's OK for quick tests with moderately large numbers:
In [1]: %timeit largest_prime_factor(600851475143)
1000 loops, best of 3: 388 µs per loop
If the complete prime factorization is sought, this is the brute-force algorithm:
def prime_factors(n):
i = 2
factors = []
while i * i <= n:
if n % i:
i += 1
else:
n //= i
factors.append(i)
if n > 1:
factors.append(n)
return factors
Ok. So you said you understand the basics, but you're not sure EXACTLY how it works. First of all, this is a great answer to the Project Euler question it stems from. I've done a lot of research into this problem and this is by far the simplest response.
For the purpose of explanation, I'll let n = 20. To run the real Project Euler problem, let n = 600851475143.
n = 20
i = 2
while i * i < n:
while n%i == 0:
n = n / i
i = i + 1
print (n)
This explanation uses two while loops. The biggest thing to remember about while loops is that they run until they are no longer true.
The outer loop states that while i * i isn't greater than n (because the largest prime factor will never be larger than the square root of n), add 1 to i after the inner loop runs.
The inner loop states that while i divides evenly into n, replace n with n divided by i. This loop runs continuously until it is no longer true. For n=20 and i=2, n is replaced by 10, then again by 5. Because 2 doesn't evenly divide into 5, the loop stops with n=5 and the outer loop finishes, producing i+1=3.
Finally, because 3 squared is greater than 5, the outer loop is no longer true and prints the result of n.
Thanks for posting this. I looked at the code forever before realizing how exactly it worked. Hopefully, this is what you're looking for in a response. If not, let me know and I can explain further.
It looks like people are doing the Project Euler thing where you code the solution yourself. For everyone else who wants to get work done, there's the primefac module which does very large numbers very quickly:
#!python
import primefac
import sys
n = int( sys.argv[1] )
factors = list( primefac.primefac(n) )
print '\n'.join(map(str, factors))
For prime number generation I always use the Sieve of Eratosthenes:
def primes(n):
if n<=2:
return []
sieve=[True]*(n+1)
for x in range(3,int(n**0.5)+1,2):
for y in range(3,(n//x)+1,2):
sieve[(x*y)]=False
return [2]+[i for i in range(3,n,2) if sieve[i]]
In [42]: %timeit primes(10**5)
10 loops, best of 3: 60.4 ms per loop
In [43]: %timeit primes(10**6)
1 loops, best of 3: 1.01 s per loop
You can use Miller-Rabin primality test to check whether a number is prime or not. You can find its Python implementations here.
Always use timeit module to time your code, the 2nd one takes just 15us:
def func():
n = 600851475143
i = 2
while i * i < n:
while n % i == 0:
n = n / i
i = i + 1
In [19]: %timeit func()
1000 loops, best of 3: 1.35 ms per loop
def func():
i=1
while i<100:i+=1
....:
In [21]: %timeit func()
10000 loops, best of 3: 15.3 us per loop
If you are looking for pre-written code that is well maintained, use the function sympy.ntheory.primefactors from SymPy.
It returns a sorted list of prime factors of n.
>>> from sympy.ntheory import primefactors
>>> primefactors(6008)
[2, 751]
Pass the list to max() to get the biggest prime factor: max(primefactors(6008))
In case you want the prime factors of n and also the multiplicities of each of them, use sympy.ntheory.factorint.
Given a positive integer n, factorint(n) returns a dict containing the
prime factors of n as keys and their respective multiplicities as
values.
>>> from sympy.ntheory import factorint
>>> factorint(6008) # 6008 = (2**3) * (751**1)
{2: 3, 751: 1}
The code is tested against Python 3.6.9 and SymPy 1.1.1.
"""
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?
"""
from sympy import primefactors
print(primefactors(600851475143)[-1])
def find_prime_facs(n):
list_of_factors=[]
i=2
while n>1:
if n%i==0:
list_of_factors.append(i)
n=n/i
i=i-1
i+=1
return list_of_factors
Isn't largest prime factor of 27 is 3 ??
The above code might be fastest,but it fails on 27 right ?
27 = 3*3*3
The above code returns 1
As far as I know.....1 is neither prime nor composite
I think, this is the better code
def prime_factors(n):
factors=[]
d=2
while(d*d<=n):
while(n>1):
while n%d==0:
factors.append(d)
n=n/d
d+=1
return factors[-1]
Another way of doing this:
import sys
n = int(sys.argv[1])
result = []
for i in xrange(2,n):
while n % i == 0:
#print i,"|",n
n = n/i
result.append(i)
if n == 1:
break
if n > 1: result.append(n)
print result
sample output :
python test.py 68
[2, 2, 17]
The code is wrong with 100. It should check case i * i = n:
I think it should be:
while i * i <= n:
if i * i = n:
n = i
break
while n%i == 0:
n = n / i
i = i + 1
print (n)
My code:
# METHOD: PRIME FACTORS
def prime_factors(n):
'''PRIME FACTORS: generates a list of prime factors for the number given
RETURNS: number(being factored), list(prime factors), count(how many loops to find factors, for optimization)
'''
num = n #number at the end
count = 0 #optimization (to count iterations)
index = 0 #index (to test)
t = [2, 3, 5, 7] #list (to test)
f = [] #prime factors list
while t[index] ** 2 <= n:
count += 1 #increment (how many loops to find factors)
if len(t) == (index + 1):
t.append(t[-2] + 6) #extend test list (as much as needed) [2, 3, 5, 7, 11, 13...]
if n % t[index]: #if 0 does else (otherwise increments, or try next t[index])
index += 1 #increment index
else:
n = n // t[index] #drop max number we are testing... (this should drastically shorten the loops)
f.append(t[index]) #append factor to list
if n > 1:
f.append(n) #add last factor...
return num, f, f'count optimization: {count}'
Which I compared to the code with the most votes, which was very fast
def prime_factors2(n):
i = 2
factors = []
count = 0 #added to test optimization
while i * i <= n:
count += 1 #added to test optimization
if n % i:
i += 1
else:
n //= i
factors.append(i)
if n > 1:
factors.append(n)
return factors, f'count: {count}' #print with (count added)
TESTING, (note, I added a COUNT in each loop to test the optimization)
# >>> prime_factors2(600851475143)
# ([71, 839, 1471, 6857], 'count: 1472')
# >>> prime_factors(600851475143)
# (600851475143, [71, 839, 1471, 6857], 'count optimization: 494')
I figure this code could be modified easily to get the (largest factor) or whatever else is needed. I'm open to any questions, my goal is to improve this much more as well for larger primes and factors.
In case you want to use numpy here's a way to create an array of all primes not greater than n:
[ i for i in np.arange(2,n+1) if 0 not in np.array([i] * (i-2) ) % np.arange(2,i)]
Check this out, it might help you a bit in your understanding.
#program to find the prime factors of a given number
import sympy as smp
try:
number = int(input('Enter a number : '))
except(ValueError) :
print('Please enter an integer !')
num = number
prime_factors = []
if smp.isprime(number) :
prime_factors.append(number)
else :
for i in range(2, int(number/2) + 1) :
"""while figuring out prime factors of a given number, n
keep in mind that a number can itself be prime or if not,
then all its prime factors will be less than or equal to its int(n/2 + 1)"""
if smp.isprime(i) and number % i == 0 :
while(number % i == 0) :
prime_factors.append(i)
number = number / i
print('prime factors of ' + str(num) + ' - ')
for i in prime_factors :
print(i, end = ' ')
This is my python code:
it has a fast check for primes and checks from highest to lowest the prime factors.
You have to stop if no new numbers came out. (Any ideas on this?)
import math
def is_prime_v3(n):
""" Return 'true' if n is a prime number, 'False' otherwise """
if n == 1:
return False
if n > 2 and n % 2 == 0:
return False
max_divisor = math.floor(math.sqrt(n))
for d in range(3, 1 + max_divisor, 2):
if n % d == 0:
return False
return True
number = <Number>
for i in range(1,math.floor(number/2)):
if is_prime_v3(i):
if number % i == 0:
print("Found: {} with factor {}".format(number / i, i))
The answer for the initial question arrives in a fraction of a second.
Below are two ways to generate prime factors of given number efficiently:
from math import sqrt
def prime_factors(num):
'''
This function collectes all prime factors of given number and prints them.
'''
prime_factors_list = []
while num % 2 == 0:
prime_factors_list.append(2)
num /= 2
for i in range(3, int(sqrt(num))+1, 2):
if num % i == 0:
prime_factors_list.append(i)
num /= i
if num > 2:
prime_factors_list.append(int(num))
print(sorted(prime_factors_list))
val = int(input('Enter number:'))
prime_factors(val)
def prime_factors_generator(num):
'''
This function creates a generator for prime factors of given number and generates the factors until user asks for them.
It handles StopIteration if generator exhausted.
'''
while num % 2 == 0:
yield 2
num /= 2
for i in range(3, int(sqrt(num))+1, 2):
if num % i == 0:
yield i
num /= i
if num > 2:
yield int(num)
val = int(input('Enter number:'))
prime_gen = prime_factors_generator(val)
while True:
try:
print(next(prime_gen))
except StopIteration:
print('Generator exhausted...')
break
else:
flag = input('Do you want next prime factor ? "y" or "n":')
if flag == 'y':
continue
elif flag == 'n':
break
else:
print('Please try again and enter a correct choice i.e. either y or n')
Since nobody has been trying to hack this with old nice reduce method, I'm going to take this occupation. This method isn't flexible for problems like this because it performs loop of repeated actions over array of arguments and there's no way how to interrupt this loop by default. The door open after we have implemented our own interupted reduce for interrupted loops like this:
from functools import reduce
def inner_func(func, cond, x, y):
res = func(x, y)
if not cond(res):
raise StopIteration(x, y)
return res
def ireducewhile(func, cond, iterable):
# generates intermediary results of args while reducing
iterable = iter(iterable)
x = next(iterable)
yield x
for y in iterable:
try:
x = inner_func(func, cond, x, y)
except StopIteration:
break
yield x
After that we are able to use some func that is the same as an input of standard Python reduce method. Let this func be defined in a following way:
def division(c):
num, start = c
for i in range(start, int(num**0.5)+1):
if num % i == 0:
return (num//i, i)
return None
Assuming we want to factor a number 600851475143, an expected output of this function after repeated use of this function should be this:
(600851475143, 2) -> (8462696833 -> 71), (10086647 -> 839), (6857, 1471) -> None
The first item of tuple is a number that division method takes and tries to divide by the smallest divisor starting from second item and finishing with square root of this number. If no divisor exists, None is returned.
Now we need to start with iterator defined like this:
def gener(prime):
# returns and infinite generator (600851475143, 2), 0, 0, 0...
yield (prime, 2)
while True:
yield 0
Finally, the result of looping is:
result = list(ireducewhile(lambda x,y: div(x), lambda x: x is not None, iterable=gen(600851475143)))
#result: [(600851475143, 2), (8462696833, 71), (10086647, 839), (6857, 1471)]
And outputting prime divisors can be captured by:
if len(result) == 1: output = result[0][0]
else: output = list(map(lambda x: x[1], result[1:]))+[result[-1][0]]
#output: [2, 71, 839, 1471]
Note:
In order to make it more efficient, you might like to use pregenerated primes that lies in specific range instead of all the values of this range.
You shouldn't loop till the square root of the number! It may be right some times, but not always!
Largest prime factor of 10 is 5, which is bigger than the sqrt(10) (3.16, aprox).
Largest prime factor of 33 is 11, which is bigger than the sqrt(33) (5.5,74, aprox).
You're confusing this with the propriety which states that, if a number has a prime factor bigger than its sqrt, it has to have at least another one other prime factor smaller than its sqrt. So, with you want to test if a number is prime, you only need to test till its sqrt.
def prime(n):
for i in range(2,n):
if n%i==0:
return False
return True
def primefactors():
m=int(input('enter the number:'))
for i in range(2,m):
if (prime(i)):
if m%i==0:
print(i)
return print('end of it')
primefactors()
Another way that skips even numbers after 2 is handled:
def prime_factors(n):
factors = []
d = 2
step = 1
while d*d <= n:
while n>1:
while n%d == 0:
factors.append(d)
n = n/d
d += step
step = 2
return factors

how can i check if number entered is prime and if not find its prime factors in python? [duplicate]

Two part question:
Trying to determine the largest prime factor of 600851475143, I found this program online that seems to work. The problem is, I'm having a hard time figuring out how it works exactly, though I understand the basics of what the program is doing. Also, I'd like if you could shed some light on any method you may know of finding prime factors, perhaps without testing every number, and how your method works.
Here's the code that I found online for prime factorization [NOTE: This code is incorrect. See Stefan's answer below for better code.]:
n = 600851475143
i = 2
while i * i < n:
while n % i == 0:
n = n / i
i = i + 1
print(n)
#takes about ~0.01secs
Why is that code so much faster than this code, which is just to test the speed and has no real purpose other than that?
i = 1
while i < 100:
i += 1
#takes about ~3secs
This question was the first link that popped up when I googled "python prime factorization".
As pointed out by #quangpn88, this algorithm is wrong (!) for perfect squares such as n = 4, 9, 16, ... However, #quangpn88's fix does not work either, since it will yield incorrect results if the largest prime factor occurs 3 or more times, e.g., n = 2*2*2 = 8 or n = 2*3*3*3 = 54.
I believe a correct, brute-force algorithm in Python is:
def largest_prime_factor(n):
i = 2
while i * i <= n:
if n % i:
i += 1
else:
n //= i
return n
Don't use this in performance code, but it's OK for quick tests with moderately large numbers:
In [1]: %timeit largest_prime_factor(600851475143)
1000 loops, best of 3: 388 µs per loop
If the complete prime factorization is sought, this is the brute-force algorithm:
def prime_factors(n):
i = 2
factors = []
while i * i <= n:
if n % i:
i += 1
else:
n //= i
factors.append(i)
if n > 1:
factors.append(n)
return factors
Ok. So you said you understand the basics, but you're not sure EXACTLY how it works. First of all, this is a great answer to the Project Euler question it stems from. I've done a lot of research into this problem and this is by far the simplest response.
For the purpose of explanation, I'll let n = 20. To run the real Project Euler problem, let n = 600851475143.
n = 20
i = 2
while i * i < n:
while n%i == 0:
n = n / i
i = i + 1
print (n)
This explanation uses two while loops. The biggest thing to remember about while loops is that they run until they are no longer true.
The outer loop states that while i * i isn't greater than n (because the largest prime factor will never be larger than the square root of n), add 1 to i after the inner loop runs.
The inner loop states that while i divides evenly into n, replace n with n divided by i. This loop runs continuously until it is no longer true. For n=20 and i=2, n is replaced by 10, then again by 5. Because 2 doesn't evenly divide into 5, the loop stops with n=5 and the outer loop finishes, producing i+1=3.
Finally, because 3 squared is greater than 5, the outer loop is no longer true and prints the result of n.
Thanks for posting this. I looked at the code forever before realizing how exactly it worked. Hopefully, this is what you're looking for in a response. If not, let me know and I can explain further.
It looks like people are doing the Project Euler thing where you code the solution yourself. For everyone else who wants to get work done, there's the primefac module which does very large numbers very quickly:
#!python
import primefac
import sys
n = int( sys.argv[1] )
factors = list( primefac.primefac(n) )
print '\n'.join(map(str, factors))
For prime number generation I always use the Sieve of Eratosthenes:
def primes(n):
if n<=2:
return []
sieve=[True]*(n+1)
for x in range(3,int(n**0.5)+1,2):
for y in range(3,(n//x)+1,2):
sieve[(x*y)]=False
return [2]+[i for i in range(3,n,2) if sieve[i]]
In [42]: %timeit primes(10**5)
10 loops, best of 3: 60.4 ms per loop
In [43]: %timeit primes(10**6)
1 loops, best of 3: 1.01 s per loop
You can use Miller-Rabin primality test to check whether a number is prime or not. You can find its Python implementations here.
Always use timeit module to time your code, the 2nd one takes just 15us:
def func():
n = 600851475143
i = 2
while i * i < n:
while n % i == 0:
n = n / i
i = i + 1
In [19]: %timeit func()
1000 loops, best of 3: 1.35 ms per loop
def func():
i=1
while i<100:i+=1
....:
In [21]: %timeit func()
10000 loops, best of 3: 15.3 us per loop
If you are looking for pre-written code that is well maintained, use the function sympy.ntheory.primefactors from SymPy.
It returns a sorted list of prime factors of n.
>>> from sympy.ntheory import primefactors
>>> primefactors(6008)
[2, 751]
Pass the list to max() to get the biggest prime factor: max(primefactors(6008))
In case you want the prime factors of n and also the multiplicities of each of them, use sympy.ntheory.factorint.
Given a positive integer n, factorint(n) returns a dict containing the
prime factors of n as keys and their respective multiplicities as
values.
>>> from sympy.ntheory import factorint
>>> factorint(6008) # 6008 = (2**3) * (751**1)
{2: 3, 751: 1}
The code is tested against Python 3.6.9 and SymPy 1.1.1.
"""
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?
"""
from sympy import primefactors
print(primefactors(600851475143)[-1])
def find_prime_facs(n):
list_of_factors=[]
i=2
while n>1:
if n%i==0:
list_of_factors.append(i)
n=n/i
i=i-1
i+=1
return list_of_factors
Isn't largest prime factor of 27 is 3 ??
The above code might be fastest,but it fails on 27 right ?
27 = 3*3*3
The above code returns 1
As far as I know.....1 is neither prime nor composite
I think, this is the better code
def prime_factors(n):
factors=[]
d=2
while(d*d<=n):
while(n>1):
while n%d==0:
factors.append(d)
n=n/d
d+=1
return factors[-1]
Another way of doing this:
import sys
n = int(sys.argv[1])
result = []
for i in xrange(2,n):
while n % i == 0:
#print i,"|",n
n = n/i
result.append(i)
if n == 1:
break
if n > 1: result.append(n)
print result
sample output :
python test.py 68
[2, 2, 17]
The code is wrong with 100. It should check case i * i = n:
I think it should be:
while i * i <= n:
if i * i = n:
n = i
break
while n%i == 0:
n = n / i
i = i + 1
print (n)
My code:
# METHOD: PRIME FACTORS
def prime_factors(n):
'''PRIME FACTORS: generates a list of prime factors for the number given
RETURNS: number(being factored), list(prime factors), count(how many loops to find factors, for optimization)
'''
num = n #number at the end
count = 0 #optimization (to count iterations)
index = 0 #index (to test)
t = [2, 3, 5, 7] #list (to test)
f = [] #prime factors list
while t[index] ** 2 <= n:
count += 1 #increment (how many loops to find factors)
if len(t) == (index + 1):
t.append(t[-2] + 6) #extend test list (as much as needed) [2, 3, 5, 7, 11, 13...]
if n % t[index]: #if 0 does else (otherwise increments, or try next t[index])
index += 1 #increment index
else:
n = n // t[index] #drop max number we are testing... (this should drastically shorten the loops)
f.append(t[index]) #append factor to list
if n > 1:
f.append(n) #add last factor...
return num, f, f'count optimization: {count}'
Which I compared to the code with the most votes, which was very fast
def prime_factors2(n):
i = 2
factors = []
count = 0 #added to test optimization
while i * i <= n:
count += 1 #added to test optimization
if n % i:
i += 1
else:
n //= i
factors.append(i)
if n > 1:
factors.append(n)
return factors, f'count: {count}' #print with (count added)
TESTING, (note, I added a COUNT in each loop to test the optimization)
# >>> prime_factors2(600851475143)
# ([71, 839, 1471, 6857], 'count: 1472')
# >>> prime_factors(600851475143)
# (600851475143, [71, 839, 1471, 6857], 'count optimization: 494')
I figure this code could be modified easily to get the (largest factor) or whatever else is needed. I'm open to any questions, my goal is to improve this much more as well for larger primes and factors.
In case you want to use numpy here's a way to create an array of all primes not greater than n:
[ i for i in np.arange(2,n+1) if 0 not in np.array([i] * (i-2) ) % np.arange(2,i)]
Check this out, it might help you a bit in your understanding.
#program to find the prime factors of a given number
import sympy as smp
try:
number = int(input('Enter a number : '))
except(ValueError) :
print('Please enter an integer !')
num = number
prime_factors = []
if smp.isprime(number) :
prime_factors.append(number)
else :
for i in range(2, int(number/2) + 1) :
"""while figuring out prime factors of a given number, n
keep in mind that a number can itself be prime or if not,
then all its prime factors will be less than or equal to its int(n/2 + 1)"""
if smp.isprime(i) and number % i == 0 :
while(number % i == 0) :
prime_factors.append(i)
number = number / i
print('prime factors of ' + str(num) + ' - ')
for i in prime_factors :
print(i, end = ' ')
This is my python code:
it has a fast check for primes and checks from highest to lowest the prime factors.
You have to stop if no new numbers came out. (Any ideas on this?)
import math
def is_prime_v3(n):
""" Return 'true' if n is a prime number, 'False' otherwise """
if n == 1:
return False
if n > 2 and n % 2 == 0:
return False
max_divisor = math.floor(math.sqrt(n))
for d in range(3, 1 + max_divisor, 2):
if n % d == 0:
return False
return True
number = <Number>
for i in range(1,math.floor(number/2)):
if is_prime_v3(i):
if number % i == 0:
print("Found: {} with factor {}".format(number / i, i))
The answer for the initial question arrives in a fraction of a second.
Below are two ways to generate prime factors of given number efficiently:
from math import sqrt
def prime_factors(num):
'''
This function collectes all prime factors of given number and prints them.
'''
prime_factors_list = []
while num % 2 == 0:
prime_factors_list.append(2)
num /= 2
for i in range(3, int(sqrt(num))+1, 2):
if num % i == 0:
prime_factors_list.append(i)
num /= i
if num > 2:
prime_factors_list.append(int(num))
print(sorted(prime_factors_list))
val = int(input('Enter number:'))
prime_factors(val)
def prime_factors_generator(num):
'''
This function creates a generator for prime factors of given number and generates the factors until user asks for them.
It handles StopIteration if generator exhausted.
'''
while num % 2 == 0:
yield 2
num /= 2
for i in range(3, int(sqrt(num))+1, 2):
if num % i == 0:
yield i
num /= i
if num > 2:
yield int(num)
val = int(input('Enter number:'))
prime_gen = prime_factors_generator(val)
while True:
try:
print(next(prime_gen))
except StopIteration:
print('Generator exhausted...')
break
else:
flag = input('Do you want next prime factor ? "y" or "n":')
if flag == 'y':
continue
elif flag == 'n':
break
else:
print('Please try again and enter a correct choice i.e. either y or n')
Since nobody has been trying to hack this with old nice reduce method, I'm going to take this occupation. This method isn't flexible for problems like this because it performs loop of repeated actions over array of arguments and there's no way how to interrupt this loop by default. The door open after we have implemented our own interupted reduce for interrupted loops like this:
from functools import reduce
def inner_func(func, cond, x, y):
res = func(x, y)
if not cond(res):
raise StopIteration(x, y)
return res
def ireducewhile(func, cond, iterable):
# generates intermediary results of args while reducing
iterable = iter(iterable)
x = next(iterable)
yield x
for y in iterable:
try:
x = inner_func(func, cond, x, y)
except StopIteration:
break
yield x
After that we are able to use some func that is the same as an input of standard Python reduce method. Let this func be defined in a following way:
def division(c):
num, start = c
for i in range(start, int(num**0.5)+1):
if num % i == 0:
return (num//i, i)
return None
Assuming we want to factor a number 600851475143, an expected output of this function after repeated use of this function should be this:
(600851475143, 2) -> (8462696833 -> 71), (10086647 -> 839), (6857, 1471) -> None
The first item of tuple is a number that division method takes and tries to divide by the smallest divisor starting from second item and finishing with square root of this number. If no divisor exists, None is returned.
Now we need to start with iterator defined like this:
def gener(prime):
# returns and infinite generator (600851475143, 2), 0, 0, 0...
yield (prime, 2)
while True:
yield 0
Finally, the result of looping is:
result = list(ireducewhile(lambda x,y: div(x), lambda x: x is not None, iterable=gen(600851475143)))
#result: [(600851475143, 2), (8462696833, 71), (10086647, 839), (6857, 1471)]
And outputting prime divisors can be captured by:
if len(result) == 1: output = result[0][0]
else: output = list(map(lambda x: x[1], result[1:]))+[result[-1][0]]
#output: [2, 71, 839, 1471]
Note:
In order to make it more efficient, you might like to use pregenerated primes that lies in specific range instead of all the values of this range.
You shouldn't loop till the square root of the number! It may be right some times, but not always!
Largest prime factor of 10 is 5, which is bigger than the sqrt(10) (3.16, aprox).
Largest prime factor of 33 is 11, which is bigger than the sqrt(33) (5.5,74, aprox).
You're confusing this with the propriety which states that, if a number has a prime factor bigger than its sqrt, it has to have at least another one other prime factor smaller than its sqrt. So, with you want to test if a number is prime, you only need to test till its sqrt.
def prime(n):
for i in range(2,n):
if n%i==0:
return False
return True
def primefactors():
m=int(input('enter the number:'))
for i in range(2,m):
if (prime(i)):
if m%i==0:
print(i)
return print('end of it')
primefactors()
Another way that skips even numbers after 2 is handled:
def prime_factors(n):
factors = []
d = 2
step = 1
while d*d <= n:
while n>1:
while n%d == 0:
factors.append(d)
n = n/d
d += step
step = 2
return factors

Print all the 3 consecutive digits that can be equal to a given number

How can I write a recursive backtracking function count(N,S) in which it prints all N-digit numbers such that the sum of each 3 consecutive digits in the number is exactly equal to S where N will be less than or equal to 10, and is from 0 to 27.
Code:
def count(S):
n = int(S)
if n % 3 == 0:
print(int(n / 3 - 1),int(n / 3),int(n / 3 + 1))
else:
print(None)
S = 27
count(S)
Sample Output:
8 9 10
I'm quite confused on how can I write this recursively.
Your current function is not recursive. To make it recursive, you'd basically have to call count(n-1, s) somewhere within the execution of count(n, s). One way to do it would be like this:
if n > 1, get possible solutions for n-1 and append any digit that still satisfied the condition
if n == 0 just return "" (it's a bit easier if the function returns strings, not actual integers)
As a generator function, this could look somewhat like this. Of course, you can just as well collect the results in a list and return them, or just get the count of such numbers and return that.
def count(n, s):
if n > 0:
for x in count(n-1, s):
for d in range(10):
y = str(d) + x
if len(y) < 3 or sum(map(int, y[:3])) == s:
yield y
else:
yield ""
for x in count(5, 15):
print(x)

Armstrong/Narcisstic number for base 16/hex

What's the goal?
My goal is to find all armstrong/narcisstic numbers in hex for a given amount of digits.
The basic idea
The basic idea is that for a set of digits e.g. [A, 3, F, 5] the sum of powers is always the same no matter the order in which they occur. That means we don't have to look at every possible number up to our maximum which should greatly reduce runtime.
What I have so far
# Armstrong numbers base 16 for n digits
import time
import itertools
from typing import Counter
pows = [[]]
def genPow(max, base):
global pows
pows = [[0]*1 for i in range(base)]
for i in range(base):
pows[i][0] = i ** max
def check(a, b):
c1 = Counter(a)
c2 = Counter(b)
diff1 = c1-c2
diff2 = c2-c1
# Check if elements in both 'sets' are equal in occurence
return (diff1 == diff2)
def armstrong(digits):
results = []
genPow(digits, 16)
# Generate all combinations without consideration of order
for set in itertools.combinations_with_replacement('0123456789abcdef', digits):
sum = 0
# Genereate sum for every 'digit' in the set
for digit in set:
sum = sum + pows[int(digit, 16)][0]
# Convert to hex
hexsum = format(sum, 'x')
# No point in comparing if the length isn't the same
if len(hexsum) == len(set):
if check(hexsum, set):
results.append(hexsum)
return sorted(results)
start_time = time.time()
print(armstrong(10))
print("--- %s seconds ---" % (time.time() - start_time))
My problem
My issue is that this is still rather slow. It takes up to ~60 seconds for 10 digits. I'm pretty sure there are ways to do this more efficient. Some things I can think of, but don't know how to do are: faster way to generate combinations, condition for stopping calc. of sum, better way to compare the sum and set, convert to hex after comparing
Any ideas how to optimize this?
Edit: I tried to compare/check a bit differently and it's already a bit faster this way https://gist.github.com/Claypaenguin/d657c4413b510be580c1bbe3e7872624 Meanwhile I'm trying to understand the recursive approach, because it looks like it'll be a lot faster.
Your problem is that combinations_with_replacement for base b and length l is returning (b+l choose b) different things. Which in your case (base 16, length 10) means that you have 5,311,735 combinations.
Each of which you then do a heavyweight calculation on.
What you need to do is filter the combinations that you are creating as you are creating them. As soon as you realize that you are not on the way to an Armstrong number, abandon that path. The calculation will seem more complicated, but it is worthwhile when it lets you skip over whole blocks of combinations without having to individually generate them.
Here is pseudocode for the heart of the technique:
# recursive search for Armstrong numbers with:
#
# base = base of desired number
# length = length of desired number
# known_digits = already chosen digits (not in order)
# max_digit = the largest digit we are allowed to add
#
# The base case is that we are past or at a solution.
#
# The recursive cases are that we lower max_digit, or add max_digit to known_digits.
#
# When we add max_digit we compute min/max sums. Looking at those we
# stop searching if our min_sum is too big or our max_sum is too small.
# We then look for leading digits in common. This may let us discover
# more digits that we need. (And if they are too big, we can't do that.)
def search(base, length, known_digits, max_digit):
digits = known_digits.copy() # Be sure we do not modify the original.
answer = []
if length < len(digits):
# We can't have any solutions.
return []
elif length == len(digits):
if digits is a solution:
return [digits]
else:
return []
elif 0 < max_digit:
answer = search(base, length, digits, max_digit-1)
digits.append(max_digit)
# We now have some answers, and known_digits. Can we find more?
find min_sum (all remaining digits are 0)
if min_sum < base**(length-1):
min_sum = base**(length-1)
find max_sum (all remaining digits are max_digit)
if base**length <= max_sum:
max_sum = base**length - 1
# Is there a possible answer between them?
if max_sum < base**(length-1) or base**length <= min_sum:
return answer # can't add more
else:
min_sum_digits = base_digits(min_sum, base)
max_sum_digits = base_digits(max_sum, base)
common_leading_digits = what digits are in common?
new_digits = what digits in common_leading_digits can't be found in our known_digits?
if 0 == len(new_digits):
return answer + search(base, length, digits, max_digit)
elif max_digit < max(new_digits):
# Can't add this digit
return answer
else:
digits.extend(new_digits)
return answer + search(base, length, digits, max_digit)
I had a small logic error, but here is working code:
def in_base (n, b):
answer = []
while 0 < n:
answer.append(n % b)
n = n // b
return answer
def powers (b, length, cached={}):
if (b, length) not in cached:
answer = []
for i in range(b):
answer.append(i**length)
cached[(b, length)] = answer
return cached[(b, length)]
def multiset_minus (a, b):
count_a = {}
for x in a:
if x not in count_a:
count_a[x] = 1
else:
count_a[x] += 1
minus_b = []
for x in b:
if x in count_a:
if 1 == count_a[x]:
count_a.pop(x)
else:
count_a[x] -= 1
else:
minus_b.append(x)
return minus_b
def armstrong_search (length, b, max_digit=None, known=None):
if max_digit is None:
max_digit = b-1
elif max_digit < 0:
return []
if known is None:
known = []
else:
known = known.copy() # Be sure not to accidentally share
if len(known) == length:
base_rep = in_base(sum([powers(b,length)[x] for x in known]), b)
if 0 == len(multiset_minus(known, base_rep)):
return [(base_rep)]
else:
return []
elif length < len(known):
return []
else:
min_sum = sum([powers(b,length)[x] for x in known])
max_sum = min_sum + (length - len(known)) * powers(b,length)[max_digit]
if min_sum < b**(length-1):
min_sum = b**(length-1)
elif b**length < min_sum:
return []
if b**length < max_sum:
max_sum = b**length - 1
elif max_sum < b**(length-1):
return []
min_sum_rep = in_base(min_sum, b)
max_sum_rep = in_base(max_sum, b)
common_digits = []
for i in range(length-1, -1, -1):
if min_sum_rep[i] == max_sum_rep[i]:
common_digits.append(min_sum_rep[i])
else:
break
new_digits = multiset_minus(known, common_digits)
if 0 == len(new_digits):
answers = armstrong_search(length, b, max_digit-1, known)
known.append(max_digit)
answers.extend(armstrong_search(length, b, max_digit, known))
return answers
else:
known.extend(new_digits)
return armstrong_search(length, b, max_digit, known)
And for a quick example:
digits = list('0123456789abcdef')
print([''.join(reversed([digits[i] for i in x])) for x in armstrong_search(10, len(digits))])
Takes a little over 2 seconds to find that the only answer is bcc6926afe.
Since itertools's combinations will return numbers in ascending order, comparing the sum of powers would be more efficient using a sorted list of its digits:
Here's a general purpose narcissic number generator that uses that mode of comparison:
import string
import itertools
def narcissic(base=10,startSize=1,endSize=None):
baseDigits = string.digits+string.ascii_uppercase+string.ascii_lowercase
if not endSize:
endSize = 1
while (base/(base-1))**(endSize+1) < base*(endSize+1): endSize += 1
def getDigits(N):
result = []
while N:
N,digit = divmod(N,base)
result.append(digit)
return result[::-1]
yield (0,"0")
allDigits = [*range(base)]
for size in range(startSize,endSize):
powers = [i**size for i in range(base)]
for digits in itertools.combinations_with_replacement(allDigits, size):
number = sum(powers[d] for d in digits)
numDigits = getDigits(number)
if digits == tuple(sorted(numDigits)):
baseNumber = "".join(baseDigits[d] for d in numDigits)
yield number, baseNumber
output:
for i,(n,bn) in enumerate(narcissic(5)): print(i+1,":",n,"-->",bn)
1 : 0 --> 0
2 : 1 --> 1
3 : 2 --> 2
4 : 3 --> 3
5 : 4 --> 4
6 : 13 --> 23
7 : 18 --> 33
8 : 28 --> 103
9 : 118 --> 433
10 : 353 --> 2403
11 : 289 --> 2124
12 : 419 --> 3134
13 : 4890 --> 124030
14 : 4891 --> 124031
15 : 9113 --> 242423
16 : 1874374 --> 434434444
17 : 338749352 --> 1143204434402
18 : 2415951874 --> 14421440424444
Using timeit to compare performance, we get a 3.5x speed improvement:
from timeit import timeit
t = timeit(lambda:list(narcissic(16,10,11)),number=1)
print("narcissic",t) # 11.006802322999999
t = timeit(lambda:armstrong(10),number=1)
print("armstrong:",t) # 40.324530023
Note that the processing time increases exponentially with each new size so a mere 3.5x speed boost will not be a meaningful as it will only push the issue to the next size

Palindromic prime number in python

So I'm trying to figure out how to find all the palindrome prime numbers between 2 numbers.
So far my code can find the palindrome but when I check for a prime number, it prints out the non-primes as well. And there are numbers which are printed multiple times.
Could you please help.
Thanks.
a = 0
b = 500
a += 1
for i in range(a,b):
if(str(i) == str(i)[::-1]):
if(i>2):
for a in range(2,i):
y = True
if(i%a==0):
y = False
break
if y:
print(i)
Based on your most recent code, you simply need to make sure that you reset y, which serves as your positive indicator of primality, for each number you test. Otherwise, it will stay False when you get to the number 4, the first composite number.
>>> a = 0
>>> b = 500
>>> a += 1
>>> for i in range(a,b):
y = True
if(str(i) == str(i)[::-1]):
if(i>2):
for a in range(2,i):
if(i%a==0):
y = False
break
if y:
print(i)
3
5
7
11
101
131
151
181
191
313
353
373
383
As you can see, all of these are prime. You can check the list of primes wolframalpha provides to be sure that no palindromic primes have been omitted. If you want to include 2, add a special case for that.
Please see my comments below:
a = 0
b = 500
a += 1
y = True
for i in range(a,b):
if(str(i) == str(i)[::-1]):
print (i) # <--- You print every number that is a palindrome
if(i>2):
for a in range(2,i):
if(i%a==0):
y = False # <--- This never gets set back to True
break
if y:
print(i)
i+=i # <--- This is doing nothing useful, because it's a "for" loop
Look at my code below, we don't need to initialize Y as well. A For-Else block works well.
a = 0
b = 500
a += 1
for i in range(a,b):
if(str(i) == str(i)[::-1]):
if(i>1):
for a in range(2,i):
if(i%a==0):
y = False
break
else:
print(i)
To get 2 included in the answer, just be sure to check the if condition as (i>1) as mentioned by #elias
Here is the pretty fast implementation based on "Sieve of Atkin" algorithm. I calculate all primes numbers up to the end and then filter only palindromic ones where number is greater or equal to start.
import math
import sys
def pal_primes(start,end):
return list(filter(lambda x: str(x)==str(x)[::-1] and x>=start, sieveOfAtkin(end)))
def sieveOfAtkin(limit):
P = [1,2,3]
sql = int(math.sqrt(limit))
r = range(1,sql+1)
sieve=[False]*(limit+1)
for x in r:
for y in r:
xx=x*x
yy=y*y
xx3 = 3*xx
n = 4*xx + yy
if n<=limit and (n%12==1 or n%12==5) : sieve[n] = not sieve[n]
n = xx3 + yy
if n<=limit and n%12==7 : sieve[n] = not sieve[n]
n = xx3 - yy
if x>y and n<=limit and n%12==11 : sieve[n] = not sieve[n]
for x in range(5,sql):
if sieve[x]:
xx=x*x
for y in range(xx,limit+1,xx):
sieve[y] = False
for p in range(5,limit):
if sieve[p] : P.append(p)
return P
if __name__=="__main__":
print(pal_primes(int(sys.argv[1]),int(sys.argv[2])))
Based on this thread:
Sieve Of Atkin Implementation in Python

Categories