Project Euler 4 with python : Largest Palindrome Product - python

I'm new to python ( and programming ) And i'm stuck in the Project Euler 4. The problem says :
"A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.
Find the largest palindrome made from the product of two 3-digit numbers."
Here's what i've come to so far :
ProductOfThree = []
ProductOfThreeSTR = []
PalindromicNumber = []
#This first for loop displays all the results possible from the product of two 3 digit Number
for k in range(100, 1000):
for j in range(k, 1000):
Result = k * j
ProductOfThree.append(Result)
#This second loop converts the list of number to a list of string
for i in ProductOfThree:
a = str(i)
ProductOfThreeSTR.append(a)
#The third loop compare the digit of each number of the list to find all the palindromic number of that list
for d in ProductOfThreeSTR:
if len(d) == 6:
if (d[0] == d[5]) and (d[1] == d[4]) and (d[2] == d[3]):
PalindromicNumber.append(d)
elif len(d) == 5:
if (d[0] == d[4]) and (d[1] == d[3]):
PalindromicNumber.append(d)
#And finally here the program display the largest number of the list, which contains only the palindromic numbers
Largest = PalindromicNumber[0]
for p in PalindromicNumber:
if Largest <= p:
Largest = p
print(Largest)
The program displays the number 99999 . After re-reading the program, i've figured out that the if statement with the len(d) == 5 is useless cause we want to display the largest number and a number with 6 digit is always greater that a number with five digit. After removing this part of the program, I'm having the result that i'm supposed to have ( 906609 ). But I'm still wondering, even if we are trying to find the palindromic number with 5 digit, normally they should be ignored when we will display the largest number of the list, so why it is giving the 99999 result?

I think that the easiest way to do this is create the palindrome list using strings but get the max using integers. This is what I came up with:
x = 100
pal = []
while x < 1000:
for i in range(100,1000):
for j in range(100,1000):
prod = str(i*j)
if prod == prod[::-1]:
pal.append(int(prod))
x = x+1
print(max(pal))

The problem is that in your last loop, when you're looking for the largest value, you compare strings instead of integers. Do this and it will give you the result you expect:
Largest = int(PalindromicNumber[0])
for p in PalindromicNumber:
if Largest <= int(p):
Largest = int(p)
According to python docs string comparison uses lexicographical ordering:
The comparison uses lexicographical ordering: first the first two items are compared, and if they differ this determines the outcome of the comparison; if they are equal, the next two items are compared, and so on, until either sequence is exhausted.

//This would be more precise
def largestpalin(n):
lowerbound=0
upperbound=0
for i in range(1,n+1):
upperbound=upperbound*10
upperbound=upperbound+9
lowebound=int(1+lowerbound/10)
maxproduct=0
for i in range(upperbound,lowerbound-1,-1):
for j in range(i,lowebound-1,-1):
product=i*j
if product<maxproduct:
break
num=product
reverse=0
while(num!=0):
rem=num%10
reverse=reverse*10+rem
num=num//10
if product==reverse and product>maxproduct:
maxproduct=reverse
return maxproduct
n=3
res=largestpalin(n)
print(res)

Related

is_prime function takes too much time to confirm if number is prime

I created a function that allows users to confirm if a number is prime. The code works great, but loses efficiency when a large number is passed through it. Any tips to cut down on time taken to process when confirming large numbers (i.e. 1999999) is prime?
Here is my code. The timing inefficiencies are a result of python asking the computer to divide number by each element in the list 'x' then placing remainder values into a separate list, to then count the number of occurrences for 0.
def is_prime(number):
x = list(range(1, number + 1,1))
numbers = []
if number < 1:
answer1 = "False. Must be positive integer greater than 1."
# For loop is iterating over list 'x'
for i in x:
# number entered divided by each element in the list to find remainder value. Remainder value
# is added to the list for each result.
numbers.append(number % i)
if number == 1:
answer1 = "False. Must be positive integer greater than 1."
# Count function/attribute used to count occurance of 0 in list 'x'
# If 0 appears more than twice on the list that indicates the number entered has more than two
# factors; thus not prime.
elif number > 1 and numbers.count(0) <= 2:
answer1 = "True"
else:
answer1 = "False"
return answer1

How would I make a try and expect block python to catch an infinite loop in a for loop

I am working on a problem where I have to output the smallest number bigger than N consisting of the same digits as N. If there is no such number, I must print "0" as the output. This is the code I have for now...
n = int(input())
copy = n+1
while True:
if sorted(str(n)) == sorted(str(copy)):
print(copy)
break
else:
copy+=1
I can not find a way to catch if a number has no such numbers, so, therefore, "0." I was thinking a try expect block but it somehow catches infinite loops. Any idea of how to implement this, or any other suggestions? Thank you!
SAMPLE INPUT/OUTPUT
input 1: 156
output 1: 165
input 2: 330
output 2: 0 (No such number fulfills the condition)
input 3: 27711
output 3: 71127
I have a different approach to the problem:
If all digits sorted in descending order, then output is always -1. For example, 321.
For other cases, we need to process the number from rightmost side (why? because we need to find the smallest of all greater numbers)
Algorithm
Traverse the given number from rightmost digit, keep traversing till you find a digit which is smaller than the previously traversed digit. For example, if the input number is “534976”, we stop at 4 because 4 is smaller than next digit 9. If we do not find such a digit, then output is “Not Possible”.
Now search the right side of above found digit ‘d’ for the smallest digit greater than ‘d’. For “534976″, the right side of 4 contains “976”. The smallest digit greater than 4 is 6.
Swap the above found two digits, we get 536974 in above example.
Now sort all digits from position next to ‘d’ to the end of number. The number that we get after sorting is the output. Finally, for above example, We get “536479” which is the next greater number for input 534976.
In last step we should check weather the result is a 32-bit number or not.
Code
def nextGreaterElement(n):
n = list(str(n))
N = len(n)
for x in range(N - 1, 0, -1):
if n[x] > n[x - 1]:
i = x - 1
break
else:
return -1
swap = i + 1
pos = i
for x in range(swap, N):
if n[pos] < n[x] < n[swap]:
swap = x
n[pos], n[swap] = n[swap], n[pos]
ans = int(''.join(n[:pos + 1]) + ''.join(sorted(n[pos + 1:])))
return ans if len(bin(ans)[2:]) < 32 else -1
print(nextGreaterElement(123))
# 132

Is there a way of checking if a value is evenly divisible by any value in a given data set?

I am currently attempting to write a simple bit of python 3 code that allows the user to tell the program which prime number it wants to find and then return the number to the user. I have hit a roadblock because I need to check if the "newprime" value is in fact a prime, which requires me to divide the value by all the previous prime numbers ("primes") and then checking if the answer is a whole number or not. Here is the current program
import numpy
primes = [2]
print("the how many-th prime would you like to calculate?")
numberOfPrime = int( input() )
x = 0
while x <= numberOfPrime:
notprime = 0 #placeholder, should be all numbers which when divided by any of the set "primes" gives a whole number
while newprime == notprime:
newprime = primes[x] + 1
primes.append(newprime)
print(primes)
x += 1
print(primes[numberOfPrime], " is the ", numberOfPrime, "-th prime number", sep="")
As you can see, I added a comment where I would have to insert the missing part.
How do I best approach this?

Python- Find nearest greater number with unique digits

I came across this problem in which you will take an integer as a input from the user and then return the nearest greater number with unique digits.
First it seem like an easy one and i wrote it's code which gave me an desired outputs but for some inputs returns an integer with repeating digits or a unique number with higher value then expected,
I want to know why my code is showing different behaviour than expected and what would be the right answer to this problem.
Also i don't know what to do when a digit will become two digit number how to make it unique eg. 9999
code
n = int(input("enter a no.:"))+1 #taking input adding 1 to make sure if the input is
#unique it should return higher no. with uniq
a =[] #creating an empty list
while n!=0: #loop to store digits in a list
a.append(n%10) #at index 0 ones digit is stored
n = int(n/10) #at index 1 tens digit is stored an so on...
while len(set(a)) != len(a): #checking if the list is unique
for i in range(0,len(a)): #
occur = a.count(a[i]) #taking occurence of a list item
if occur != 1: #if no. is repeated
a[i]+=occur-1 #incrementing the repeating digit.
a.reverse() #converting list to integer and printing
n = 0
for i in a:
n = n*10+i
print(n)
Behaviour
1.Printing repeating digits for some inputs
2.Printing Higher values than expected for some inputs
3.When a digit becomes a two digit no. it treats it like a single digit
Some outputs
enter a no.:1233
output: 1234 #desired output: 1234
enter a no.:7885
output: 7896 #desired output: 7890
enter a no.:7886
output: 8008 #desired output: 7890
enter a no.:999
output: 2013 #desired output: 1023
You're probably over complicating this for yourself.
Would something like this work rather than doing all of the conversions?
n = int(input("enter a no.:"))+1 #taking input adding 1 to make
#sure if the input is unique then
#program does't return the input itself
a = str(n) # simply convert to a string
while len(set(a)) != len(a): #checking if the string is unique
n += 1
a = str(n)
print(n)
Why not simply increment the number until you find one with unique digits?
def next_uniq(n):
a = str(n)
while len(set(a)) != len(a):
a = str(int(a) + 1)
return a
for i in [1233, 7885, 7886, 999]:
print(next_uniq(i))
# 1234, 7890, 7890, 1023

How can I display all numbers in range 0-N that are "super numbers"

The program asks the user for a number N.
The program is supposed to displays all numbers in range 0-N that are "super numbers".
Super number: is a number such that the sum of the factorials of its
digits equals the number.
Examples:
12 != 1! + 2! = 1 + 2 = 3 (it's not super)
145 = 1! + 4! + 5! = 1 + 24 + 120 (is super)
The part I seem to be stuck at is when the program displays all numbers in range 0-N that are "super numbers". I have concluded I need a loop in order to solve this, but I do not know how to go about it. So, for example, the program is supposed to read all the numbers from 0-50 and whenever the number is super it displays it. So it only displays 1 and 2 since they are considered super
enter integer: 50
2 is super
1 is super
I have written two functions; the first is a regular factorial program, and the second is a program that sums the factorials of the digits:
number = int(input ("enter integer: "))
def factorial (n):
result = 1
i = n * (n-1)
while n >= 1:
result = result * n
n = n-1
return result
#print(factorial(number))
def breakdown (n):
breakdown_num = 0
remainder = 0
if n < 10:
breakdown_num += factorial(n)
return breakdown_num
else:
while n > 10:
digit = n % 10
remainder = n // 10
breakdown_num += factorial(digit)
#print (str(digit))
#print(str(breakdown_num))
n = remainder
if n < 10 :
#print (str(remainder))
breakdown_num += factorial(remainder)
#print (str(breakdown_num))
return breakdown_num
#print(breakdown(number))
if (breakdown(number)) == number:
print(str(number)+ " is super")
Existing answers already show how to do the final loop to tie your functions together. Alternatively, you can also make use of more builtin functions and libraries, like sum, or math.factorial, and for getting the digits, you can just iterate the characters in the number's string representation.
This way, the problem can be solved in a single line of code (though it might be better to move the is-super check to a separate function).
def issuper(n):
return sum(math.factorial(int(d)) for d in str(n)) == n
N = 1000
res = [n for n in range(1, N+1) if issuper(n)]
# [1, 2, 145]
First I would slightly change how main code is executed, by moving main parts to if __name__ == '__main__', which will execute after running this .py as main file:
if __name__ == '__main__':
number = int(input ("enter integer: "))
if (breakdown(number)) == number:
print(str(number)+ " is super")
After that it seems much clearer what you should do to loop over numbers, so instead of above it would be:
if __name__ == '__main__':
number = int(input ("enter integer: "))
for i in range(number+1):
if (breakdown(i)) == i:
print(str(i)+ " is super")
Example input and output:
enter integer: 500
1 is super
2 is super
145 is super
Small advice - you don't need to call str() in print() - int will be shown the same way anyway.
I haven't done much Python in a long time but I tried my own attempt at solving this problem which I think is more readable. For what it's worth, I'm assuming when you say "displays all numbers in range 0-N" it's an exclusive upper-bound, but it's easy to make it an inclusive upper-bound if I'm wrong.
import math
def digits(n):
return (int(d) for d in str(n))
def is_super(n):
return sum(math.factorial(d) for d in digits(n)) == n
def supers_in_range(n):
return (x for x in range(n) if is_super(x))
print(list(supers_in_range(150))) # [1, 2, 145]
I would create a lookup function that tells you the factorial of a single digit number. Reason being - for 888888 you would recompute the factorial of 8 6 times - looking them up in a dict is much faster.
Add a second function that checks if a number isSuper() and then print all that are super:
# Lookup table for single digit "strings" as well as digit - no need to use a recursing
# computation for every single digit all the time - just precompute them:
faks = {0:1}
for i in range(10):
faks.setdefault(i,faks.get(i-1,1)*i) # add the "integer" digit as key
faks.setdefault(str(i), faks [i]) # add the "string" key as well
def fakN(n):
"""Returns the faktorial of a single digit number"""
if n in faks:
return faks[n]
raise ValueError("Not a single digit number")
def isSuper(number):
"Checks if the sum of each digits faktorial is the same as the whole number"
return sum(fakN(n) for n in str(number)) == number
for k in range(1000):
if isSuper(k):
print(k)
Output:
1
2
145
Use range.
for i in range(number): # This iterates over [0, N)
if (breakdown(number)) == number:
print(str(number)+ " is super")
If you want to include number N as well, write as range(number + 1).
Not quite sure about what you are asking for. From the two functions you write, it seems you have solid knowledge about Python programming. But from your question, you don't even know how to write a simple loop.
By only answering your question, what you need in your main function is:
for i in range(0,number+1):
if (breakdown(i)) == i:
print(str(i)+ " is super")
import math
def get(n):
for i in range(n):
l1 = list(str(i))
v = 0
for j in l1:
v += math.factorial(int(j))
if v == i:
print(i)
This will print all the super numbers under n.
>>> get(400000)
1
2
145
40585
I dont know how efficient the code is but it does produce the desired result :
def facto():
minr=int(input('enter the minimum range :')) #asking minimum range
maxr=int(input('enter the range maximum range :')) #asking maximum range
i=minr
while i <= maxr :
l2=[]
k=str(i)
k=list(k) #if i=[1,4,5]
for n in k: #taking each element
fact=1
while int(n) > 0: #finding factorial of each element
n=int(n)
fact=fact*n
n=n-1
l2.append(fact) #keeping factorial of each element eg : [1,24,120]
total=sum(l2) # taking the sum of l2 list eg 1+24+120 = 145
if total==i: #checking if sum is equal to the present value of i.145=145
print(total) # if sum = present value of i than print the number
i=int(i)
i=i+1
facto()
input : minr =0 , maxr=99999
output :
1
2
145
40585

Categories