Trying to find the largest palindrome that's the product of two three-digit numbers. Before I look up the infinitely more efficient and - more importantly - working solution, could you tell me what's wrong with my code? I just keep getting the empty set.
def palindrome():
n = 100
m = 100
palind = []
while n<=999:
while m<=999:
prod = n * m
if str(prod) == str(prod)[::-1] and prod > palind[0]:
palind.pop(0)
palind.append(prod)
return palind
m = m + 1
n = n + 1
return palind
print palindrome()
You have 3 problems.
Problem 1: Returning early.
while n<=999:
while m<=999:
prod = n * m
if str(prod) == str(prod)[::-1] and prod > palind[0]:
palind.pop(0)
palind.append(prod)
# Here
return palind
m = m + 1
n = n + 1
# And here
return palind
A return statement means the function is over now. It stops where it is, the caller gets the return value, and the caller goes on its way. You don't want to do that until the function is completely done with its work. Let's move the return to after the loops, when the function is done computing.
Problem 2: palind[0] is uninitialized.
while n<=999:
while m<=999:
prod = n * m
# Here v
if str(prod) == str(prod)[::-1] and prod > palind[0]:
palind.pop(0)
palind.append(prod)
m = m + 1
n = n + 1
return palind
Suppose your program is going along and it finds its first palindrome. It tries to compare it to palind[0], but there is no palind[0]! You need to take the first palindrome without trying to compare it to one that doesn't exist. Let's fix that.
Problem 3: Not resetting m.
palind = None
while n<=999:
while m<=999:
prod = n * m
if str(prod) == str(prod)[::-1]:
if palind is None or prod > palind:
palind = prod
m = m + 1
n = n + 1
return palind
After the first iteration of the n loop, you need to go back through all possible m values with n=101. You don't do that; your code keeps m at 1000, so it doesn't go through the inner loop again. You could explicitly reset m, but it's much easier to use for loops instead of whiles. With all 3 problems fixed, your code looks like
palind = None
for n in xrange(100, 1000):
for m in xrange(100, 1000):
prod = n * m
if str(prod) == str(prod)[::-1]:
if palind is None or prod > palind:
palind = prod
return palind
This shortcuts when it's impossible to return an i*j > the largest recorded and correctly returns 906609 (note, if you're in python 2, the below would work for you, but you'd prefer to use xrange instead of range to avoid creating unnecessary lists in memory):
def palindrome(floor=0, upto=999):
'''
return the largest palindrome product for all number from (but not including)
floor to (and including) upto
'''
start = upto
largest = None
for i in range(start, floor, -1): # decreasing from upto
if i * upto < largest: # if True, impossible for higher product from combo
break
for j in range(start, i-1, -1): # decrease from upto to not including i-1
product = i*j
if str(product) == str(product)[::-1]:
if product > largest:
largest = product
return largest
Usage:
>>> palindrome(99,999)
906609
>>> palindrome(10,13)
121
>>> palindrome(0,10)
9
The short-cutting is important because if given a very large number, it can take quite a while to return:
>>> palindrome(upto=100000000)
9999000000009999L
I also created a generator that hits every single combination from 0 to 999, and it returns 906609.
def palindrome(upto=1000):
return max(i*j for i in range(upto) for j in range(upto)
if str(i*j) == str(i*j)[::-1])
But when running this palindrome as in:
>>> palindrome(upto=100000000)
The complete search will search all 100000000^2, and take far too long.
I first had written it like this, with the idea that it would short-cut and avoid iterating over every possible combination, but this is incorrect, it returns 888888:
def palindrome():
start = 999
largest = 0
for i in range(start, 0, -1): # decreasing from 999
if i * 999 < largest:
return largest
for j in range(start, i, -1): # decreasing from 999 to i
if str(i*j) == str(i*j)[::-1]:
largest = i*j
It first multiplies 999 times 999, then 998 times 999, then
998*998
997*999
997*998
997*997
...
But the results aren't monotonically decreasing (that is, each result is not guaranteed to be smaller than the previous.)
You are not re-initializing m = 100, after every iteration of the outer while loop
You are returning early. Remove the return statement in the inner loop
The last return statement should NOT be inside the outer while loop.
You never initialized palind list (Thanks to #user2357112)
Suggestions:
Don't use a list to maintain the biggest number. A simple variable is enough.
You don't have to convert the number to string twice in the same expression. Store the stringified number in a variable.
Use range functions to loop through the numbers
If I were to write this program, I would have done it like this
from itertools import product
def palindrome():
numbers, result = range(1000, 100, -1), -1
for num1, num2 in product(numbers, repeat = 2):
prod = num1 * num2
sprod = str(prod)
if sprod == sprod[::-1] and prod > result:
result = prod
return result
print palindrome() # 906609
This is may not answer the question, but if you looking for to get palindromic numbers between range you can do this
def getPalindrome(lower, upper):
listPalind = []
for n in range(lower, upper):
if str(n) == str(n)[::-1]:
listPalind.append(n)
return listPalind
# Usage
print(getPalindrome(100, 300))
# Results
[101, 111, 121, 131, 141, 151, 161, 171, 181, 191, 202, 212, 222, 232, 242, 252, 262, 272, 282, 292]
def is_palindromic(s):
if s == s[::-1]:
return True
else:
return False
palind = []
for i in range(100, 1000):
for j in range(100,1000):
product = i * j
if is_palindromic(str(product)):
palind.append(product)
return max(palind)
#result :
906609
def isPalindrome(self, x: int):
temp = 0
x1 = x
while x > 0:
y = x % 10
temp = temp * 10 + y
x = x//10
if(temp == x1):
return True
else:
return False
Related
I am trying to compute the powerset of a list of prime numbers. I have already done some research and the prefered way of doing this seems to be using a line like
itertools.chain.from_iterable(itertools.combinations(primes, r) for r in range(2, len(primes) + 1))
and then iterating over all combinations to get the products with math.prod(). All in all, the code currently looks like this:
number = 200
p1 = []
# calculate all primes below specified number
for i in range(2, number + 1):
isPrime = True
for prime in p1:
if i % prime == 0:
isPrime = False
if isPrime:
p1.append(i)
Pp = []
myIterable = itertools.chain.from_iterable(itertools.combinations(p1, r) for r in range(2, len(p1) + 1))
# convert iterable to integer array of products -- The code below is extremely slow and should be improved
for x in myIterable:
newValue = math.prod(x)
if newValue <= number:
Pp.append(newValue)
This works, but it is not feasible for any "number" greater than 100 because of too high execution time. The problem is the last for loop, which takes forever to compute. Everything else performs reasonably well. The powerset has to be constricted to sets, whos products are less or equal to number, as done using the last if statement, or else the memory will explode.
The solution to this problem was to create a pointer array, which crawls through the prime array until the product of the pointed primes gets too high. The needed helper functions can be implemented like this:
def calcProductOfPointers(pointerArray, dataArray):
prod = 1
for pointer in pointerArray:
prod *= dataArray[pointer]
return prod
def incrementPointer(pointerArray, dataArray, threshold):
ret = False
for i in range(1, len(pointerArray) + 1):
index = len(pointerArray) - i
pointerArray[index] += 1
if calcProductOfPointers(pointerArray, dataArray) <= threshold and pointerArray[index] < len(dataArray):
ret = True
break
elif index > 0:
pointerArray[index] = pointerArray[index - 1] + 2
else:
break
return ret
And then the iteration over all powersets can be substituted with this code:
Pp = []
for i in range(2, len(p1) + 1): # start at a minimum of 2 prime factors
primePointers = []
for index in range(i):
primePointers.append(index)
if calcProductOfPointers(primePointers, p1) > number:
break
while calcProductOfPointers(primePointers, p1) <= number:
Pp.append(calcProductOfPointers(primePointers, p1))
if not incrementPointer(primePointers, p1, number):
break
I have the following recursive function to get the mth term of a n-bonacci sequence as shown below this question. My problem is that the use of for and while loops is totally banned from the code, so I need to get rid off
for i in range(1, n+1):
temp += n_bonacci(n,m-i)
and convert the code into something that is not a loop but nevertheless achieves the same effect. Among the things I can use, but this is not an exclusive enumeration, is: (1) use built-in functions like sum() and .join() and (2) use list comprehensions.
The full code is as follows:
def n_bonacci(n,m): #n is the number of n initial terms; m is the mth term.
if (m < n-1):
return 0
elif (m == n-1):
return 1
else:
temp = 0
#[temp += n_bonacci(n,m-i) for i in range(n)] #this is an attempt at using list comprehension
for i in range(1, n+1):
temp += n_bonacci(n,m-i)
return temp
print("n_bonacci:",n_bonacci(2,10))
print("n_bonacci:",n_bonacci(7,20))
Here's a solution that avoids any type of loop, including loops hidden inside comprehensions:
def n_bonacci_loopless(n, m):
def inner(i, c):
if i == m:
return sum(c)
else:
return inner(i+1, c[-(n-1):] + [sum(c)])
if m < n-1:
return 0
elif (m == n-1):
return 1
else:
return inner(n, [0] * (n-1) + [1])
The base cases are the same, but for recursive cases it initialises a list of collected results c with n-1 zeroes, followed by a one, the sum of which would be the correct answer for m == n.
For m > n, the inner function is called again as long as i < m, summing the list and appending the result to the end of the last n-1 elements of the list so far.
If you are allowed to use comprehensions, the answer is trivial:
def n_bonacci(n,m):
if (m < n-1):
return 0
elif (m == n-1):
return 1
else:
return sum(n_bonacci(n, m-i) for i in range(1, n+1))
You can rewrite the code as follows using list comprehensions:
def n_bonacci(n,m): #n is the number of n initial terms; m is the mth term.
if (m < n-1):
return 0
elif (m == n-1):
return 1
else:
return sum(n_bonacci(n, m-i) for i in range(1, n + 1))
print("n_bonacci:",n_bonacci(2,10))
print("n_bonacci:",n_bonacci(7,20))
To go beyond #Grismar 's answer you can write your own version of sum which doesn't use loops.
def n_bonacci_loopless(n, m):
def recsum(l, s=0):
return recsum(l[1:], s + l[0])
def inner(i, c):
if i == m:
return recsum(c)
else:
return inner(i+1, c[-(n-1):] + [recsum(c)])
if m < n-1:
return 0
elif (m == n-1):
return 1
else:
return inner(n, [0] * (n-1) + [1])
I am just getting started in Python Programming. I had a problem on checking if a given list contains alternating sequence of primes and perfect squares. The list can start with either a prime or a perfect square. I came up with a solution but it's not efficient as it generates unwanted lists. Is this possible with more efficient Python code?
First I'm creating functions to generate a list of primes as well as perfect squares up to the max value of testing list. Functions squaretest() and primecheck():
def squaretest(num):
sqlist=[]
i=1
while i**2 <= num:
sqlist.append(i**2)
i+=1
return sqlist
def primecheck(num):
primelist=[]
for i in range(2,num + 1):
for p in range(2,i):
if (i % p) == 0:
break
else:
primelist.append(i)
return primelist
Then I am dividing the given list into lists of even index and odd index elements and checking all elements of them against the primelist and the squarelist:
def primesquare(l):
if len(l)==1:
primelist = primecheck(l[0])
sqlist = squaretest(l[0])
return (l[0] in primelist) or (l[0] in sqlist)
else:
ol=[]
el=[]
for i in range(0,len(l),2):
ol.append(l[i])
for p in range (1, len(l),2):
el.append(l[p])
primelist = primecheck(max(l))
sqlist = squaretest (max(l))
return((all(x in primelist for x in el)) == True and (all(y in sqlist for y in ol)) == True) or ((all(x in primelist for x in ol)) == True and (all(y in sqlist for y in el)) == True)
It works.
Any suggestions will be really helpful.
You can use sets to check if all members of a list are in another list.
def primesquare(l):
if len(l) == 0:
return True
primelist = set(primecheck(max(l)))
sqlist = set(squaretest(max(l)))
ol = set(l[::2])
el = set(l[1::2])
odds_are_primes = ol.issubset(primelist)
odds_are_squares = ol.issubset(sqlist)
evens_are_primes = el.issubset(primelist)
evens_are_squares = el.issubset(sqlist)
return (odds_are_primes and evens_are_squares) or (odds_are_squares and evens_are_primes)
I came up with a solution but it's not efficient as it generates
unwanted lists.
Assuming the unwanted lists are the two lists representing the even and odd elements, then we can fix that. (Eliminating the primes and squares list is a whole 'nother problem.) Below is my rework of your code -- we don't create addtional lists but rather with a couple of reusable ranges which are objects that produce integer sequences as needed, but not stored in memory.
Your any() design is efficient in that the arguments are generator expressions, not lists, which are computed as needed. As soon as a flaw is found in the array, the whole thing stops and returns False--it doesn't need to process the rest:
def squares(number):
return {x * x for x in range(int(number ** 0.5) + 1)}
def primes(number):
prime_set = set()
for i in range(2, number + 1):
for p in range(2, int(i ** 0.5) + 1):
if (i % p) == 0:
break
else: # no break
prime_set.add(i)
return prime_set
def primesquare(array):
if not array:
return True # define as the problem demands
length, maximum = len(array), max(array)
odd, even = range(0, length, 2), range(1, length, 2)
prime_set, square_set = primes(maximum), squares(maximum)
return all(array[i] in prime_set for i in even) and all(array[i] in square_set for i in odd) or all(array[i] in prime_set for i in odd) and all(array[i] in square_set for i in even)
I admire #AndreySemakin's set-based solution (+1), and use sets above, but his solution generates the same lists you want to eliminate (just in the form of sets).
I came up with this solution:
def primesquare(lst):
# checking if the first element is either perfect square or a prime
if not lst or (not checksquare(lst[0]) and not checkprime(lst[0])):
return False
length = len(lst)
if length == 1:
return True
if checksquare(lst[0]):
# if first element is square then make s(quare)=2 and p(rime)=1
s, p = 2, 1
else:
# if first element is prime then make s=1 and p=2
s, p = 1, 2
# running perfect square loop from s to len-1 with gap of 2 and checking condition
for i in range(s, length, 2):
if not checksquare(lst[i]):
return False
# running prime loop from p to len-1 with gap of 2
for i in range(p, length, 2):
if not checkprime(lst[i]):
return False
return True
def checksquare(n): # function to check perfect square
if n < 0:
return False
if 0 <= n <= 1:
return True
for i in range(int(n ** 0.5) + 1):
if i * i == n:
return True
return False
def checkprime(n): # function to check prime
if n < 2:
return False
if n % 2 == 0:
return n == 2
for i in range(3, int(n ** 0.5) + 1, 2):
if n % i == 0:
return False
return True
I've a small Python (2.7.10) script, which you can see below.
def numbers_calc(max_num, num_step):
"""Returns every number from 0 to max_num with num_step as step."""
n = 0
l = []
while n < max_num + 1:
l.append(n)
n += n * num_step
return l
n_l = []
n_l.append(numbers_calc(25, 1))
print "Here are the numbers."
print n_l
The function numbers_calc is meant to take all the given args, form a list, and populate it with numbers (with num_step as the step when calculating) before it reaches max_num + 1. The script then does return it's local list named l.
However, every time I run the script, I encounter MemoryError. Here's what Python returned when I ran the script:
Traceback (most recent call last):
File "num.py", line 13, in <module>
n_l.append(numbers_calc(25, 1))
File "ex33.py", line 7, in numbers_calc
l.extend(i)
MemoryError
I tried looking it up, saw nothing helpful. I hope you can help me!
n starts at 0. n += n * num_step adds 0 to n. n never changes, and your loop keeps adding items to the list forever.
Cause n to change somehow.
The issue is in the line -
n += n * num_step
Here, you initialized n as 0 , and then you are multiplying n and num_step , whose result would always be 0 , and then adding it to n . So n always stays at 0 . If you are Try to loop from 0 to max_num+1 for every num_step, you should use range() function, Example -
def numbers_calc(max_num, num_step):
"""Returns every number from 0 to max_num with num_step as step."""
l = []
for i in range(0,max_num + 1,num_step):
l.append(i)
return l
anything times 0 is always going to be 0 so you have an infinite loop settingn = 0 set n to 1 initially:
def numbers_calc(max_num, num_step):
"""Returns every number from 0 to max_num with num_step as step."""
n = 1
l = []
while n < max_num + 1:
l.append(n)
n += n * num_step
print(n)
return l
n_l = []
n_l.append(numbers_calc(25, 1))
Output:
[[1, 2, 4, 8, 16]]
If you want a list of number just use the return value:
nl = numbers_calc(25, 1)
Which will give you [1, 2, 4, 8, 16]
If you actually want every number from 0 to max_num with num_step use += not *= and leave n at 0:
def numbers_calc(max_num, num_step):
"""Returns every number from 0 to max_num with num_step as step."""
n = 0
l = []
while n < max_num + 1:
l.append(n)
n += num_step
print(n)
return l
Or simply return range with a step:
def numbers_calc(max_num, num_step):
"""Returns every number from 0 to max_num with num_step as step."""
return list(range(max_num + 1,num_step))
You should be aware that if the step is not a multiple of max_num then you are not going to get max_num i.e numbers_calc(25, 2) will go to 24 .
Thanks everybody for helping! Didn't even realise I had math problems there. Thank you all! By the way, here's the final version of my script.
def numbers_calc(max_num, num_step):
"""Returns every number from 0 to max_num with num_step as step."""
i = 0
l = []
while i < max_num + 1:
l.append(i)
i += num_step
return l
n_l = numbers_calc(25, 5)
print "Here are the numbers."
print n_l
Project Euler Problem #27 is as follows:
Euler discovered the remarkable quadratic formula:
n² + n + 41
It turns out that the formula will produce 40 primes for the
consecutive values n = 0 to 39. However, when n = 40, 402 + 40 + 41 =
40(40 + 1) + 41 is divisible by 41, and certainly when n = 41, 41² +
41 + 41 is clearly divisible by 41.
The incredible formula n² − 79n + 1601 was discovered, which produces
80 primes for the consecutive values n = 0 to 79. The product of the
coefficients, −79 and 1601, is −126479.
Considering quadratics of the form:
n² + an + b, where |a| < 1000 and |b| < 1000
where |n| is the modulus/absolute value of n e.g. |11| = 11 and |−4| =
4 Find the product of the coefficients, a and b, for the quadratic
expression that produces the maximum number of primes for consecutive
values of n, starting with n = 0.
And this is my solution:
from math import sqrt, fabs
def eSieve(rnge):
rootedrange = int(sqrt(rnge))
mydict = dict([(_, True) for _ in range(2, rootedrange)])
for i in range(2, rootedrange):
if mydict[i] == True:
for j in range(i**2, rnge, i):
mydict[j] = False
mylist = []
for key in mydict.keys():
if mydict[key] is True:
mylist.append(key)
return mylist
primes = eSieve(87400)
def isPrime(n):
i = 0
while primes[i] <= n:
if primes[i] == n: return True
i+=1
return False
arange = 0
brange = 0
nrange = 0
for a in range(-1000, 1001):
for b in range(-1000, 1001):
n = 0
formula = n*n + a*n + b
print(formula)
while(isPrime(fabs(formula))):
n+=1
if n > nrange:
arange = a
brange = b
crange = c
print(arange * brange)
I do not know why is it continuously throwing this error:
Traceback (most recent call last):
File "D:\Programming\ProjectEuler\p27.py", line 33, in <module>
while(isPrime(fabs(formula))):
File "D:\Programming\ProjectEuler\p27.py", line 20, in isPrime
while primes[i] <= n:
IndexError: list index out of range
Can anyone tell where and how is my program getting out of lists range? It's very abnormal. Why is this happening?
Let's see what happens if you want to see if 1000000 is a prime:
i = 0
while primes[i] <= n:
if primes[i] == n: return True
i+=1
return False
None of the sieved primes is larger than 1000000 so your while condition is never fulfilled. First rule of Python is to never use while loop (except when you cannot use any other loop). Here you can easily replace it with for:
for i in primes:
if i == n:
return True
return False
But this is exactly what the in operator is set to replace:
return n in primes
In addition for your isPrime reimplementing the Python core feature n in primes, the
item in list gets slower than item in set as the number of items grows.
Thus for fastest code with almost least typing you can do:
>>> primes = eSieve(87400)
>>> prime_set = set(primes)
>>> 13 in prime_set
True
>>> # or if you want a function:
>>> is_prime = prime_set.__contains__
>>> is_prime(13)
True
__contains__ magic method of the set returns true if the given value is in the set - this is much faster using it directly than wrapping in operator in a function.
If isPrime(n) should return whether n is in the previously created list primes, then you can easily write:
def isPrime(n):
return n in primes
(Your solution fails, because your prime list is too short for n = 1000. The largest prime is 293, thus the while condition is always fulfilled. But after a while you want to compare primes[62] with n, which is out of range.)