Generalized project euler #4 - python

I tried some basic optimizations, to cut down on the number of operations for the general euler problem #4:
def is_palindrome(num):
return str(num) == str(num)[::-1]
def fn(n):
max_palindrome = 1
for x in range(n,1,-1):
for y in range(n,x-1,-1):
if is_palindrome(x*y) and x*y > max_palindrome:
max_palindrome = x*y
elif x * y < max_palindrome:
break
return max_palindrome
print fn(999)
Can I/how do I optimize this further? (assume it's the general solution, for factors of at most n rather than at most 999).

Some small optimizations: you can break out early of the x-loop and reduce the number of calls to is_palindrome by swapping the checks around a bit (untested):
def fn(n):
max_palindrome = 1
for x in range(n,1,-1):
if x * n <= max_palindrome: # nothing bigger possible for remaining x
break
for y in range(n,x-1,-1):
if x * y <= max_palindrome: #nothing bigger possible for current x
break
if is_palindrome(x*y):
max_palindrome = x*y
return max_palindrome

Related

What is the complexity of this pythagorean triplet function?

def tuplePyth(n):
list_=[]
for x in range(1, n):
for y in range(x + 1, (n - x) // 2):
for z in range (y + 1, n - x - y):
if smallestTrip(x, y, z)==False:
list_.append([x,y,z])
print (list_)
def pythTrue(a,b,c):
(A,B,C) = (a*a,b*b,c*c)
if A + B == C or B + C == A or A + C == B:
return True
def smallestTrip(a,b,c):
if pythTrue(a,b,c) == True:
if (a+b+c)%12 == 0:
return True
else:
return False
smallestTrip checks if x,y,z are multiples of the basic 3,4,5 right triangle.
The goal is to generate all possible pythagorean triplets the sum of which is less than an inputed sum, n.
(these triplets must NOT be multiples of the (3,4,5) triangle.)
Is the complexity here O(nnlogn)?
The other functions are O(1) and you have three loops with respect to n in the original problem. So the complexity is O(n * n * n) = O(n^3)
This question may provide further illumination Time complexity of nested for-loop

Finding number of pythagorean triples in a list using python?

I am coding a solution for a problem where the code will find the number of Pythagorean triples in a list given a list a. However, when I submit my code to the auto-grader, there are some test cases where my code fails, but I have no idea what went wrong. Please help me point out my mistake.....
def Q3(a):
lst = [i ** 2 for i in a]
lst.sort()
ans = 0
for x in lst:
for y in lst:
if (x + y) in lst:
ans += 1
return ans // 2
"Pythagorean triples" are integer solutions to the Pythagorean Theorem, for example, 32+42=52. Given a list of positive integers, find the number of Pythagorean triplets. Two Pythagorean triplets are different if at least one integer is different.
Implementation
· Implement a function Q3(A), where the A is a list of positive integers. The size of list A is up to 250.
· There are no duplicates in the list A
· This function returns the number of Pythagorean triplets.
Sample
· Q3( [3,4,6,5] ) = 1
· Q3( [4,5,6] ) = 0
Simple but not very efficient solution would be to loop through the list of numbers in the range (I have taken number from 1 to 100 for instance) in 3 nested for loops as below. But it would be slower as for 100 elements, it needs to have 100^3 operations
triplets = []
for base in range(1,101):
for height in range(1,101):
for hypotenuse in range(1,101):
# check if forms a triplet
if hypotenuse**2 == base**2 + height**2:
triplets.append(base, height, hypotenuse)
This can be made slightly more efficient (there are better solutions)
by calculating hypotenuse for each base and height combination and then check if the hypotenuse is an Integer
triplets = []
for base in range(1,101):
for height in range(1,101):
hypotenuse = math.sqrt(base**2 + height**2)
# check if hypotenuse is integer by ramiander division by 1
if hypotenuse%1==0:
triplets.append(base, height, hypotenuse)
# the above solution written a list comprehension
a = range(1,101)
[(i,j,math.sqrt(i*i+j*j)) for i in a for j in a if math.sqrt(i*i+j*j)%1==0]
If you consider (3,4,5) and (3,5,4) as different, use a set instead of list and get the len(triplets_set) in the end
Problem 1: Suppose your input is
[3,4,5,5,5]
Though it's somewhat unclear in your question, my presumption is that this should count as three Pythogorean triples, each using one of the three 5s.
Your function would only return 1.
Problem 2: As Sayse points out, your "triple" might be trying to use the same number twice.
You would be better off using itertools.combinations to get distinct combinations from your squares list, and counting how many suitable triples appear.
from itertools import combinations
def Q3(a):
squares = [i**2 for i in a]
squares.sort()
ans = 0
for x,y,z in combinations(squares, 3):
if x + y == z:
ans += 1
return ans
Given the constraints of the input you now added to your question with an edit, I don't think there's anything logically wrong with your implementation. The only type of test cases that your code can fail to pass has to be performance-related as you are using one of the slowest solutions by using 3 nested loops iterating over the full range of the list (the in operator itself is implemented with a loop).
Since the list is sorted and we want x < y < z, we should make y start from x + 1 and make z start from y + 1. And since given an x, the value of x depends on the value of y, for each given y we can increment z until z * z < x * x + y * y no longer holds, and if z * z == x * x + y * y at that point, we've found a Pythagorean triple. This allows y and z to sweep through the values above x only once and therefore reduces the time complexity from O(n^3) to O(n^2), making it around 40 times faster when the size of the list is 250:
def Q3(a):
lst = [i * i for i in sorted(a)]
ans = 0
for x in range(len(lst) - 2):
y = x + 1
z = y + 1
while z < len(lst):
while z < len(lst) and lst[z] < lst[x] + lst[y]:
z += 1
if z < len(lst) and lst[z] == lst[x] + lst[y]:
ans += 1
y += 1
return ans

Square Root using Babylonian Method returns wrong value

Trying to use a loop function to find the square root of a number.
I'm trying to use the Babylonian method but it will not return the correct answer. If someone could point out where I have an error that would be much appreciated.
def sqrt(number, guess, threshold):
x = number / 2
prev_x = x + 2 * threshold
while abs(prev_x - x) > threshold:
prev_x = x
x = (x + guess / x) / 2
square_root = x
return square_root
test = sqrt(81, 7, 0.01)
print (test)
Change
x = (x+guess/x)/2
as this would progress to square root of guess. Change it to
x = (x+number/x)/2
Move return statement out of the while loop
initialize x to guess instead of number/2
There's no need for a guess variable at all. Your x = number/2 is your initial guess already, and by using an arbitrarily assigned guess in your computation without updating it you certainly would not get the right number.
Replace guess with number instead, and return only when the while loop is finished, and your code would work:
def sqrt(number,guess,threshold):
x = number/2
prev_x = x+2*threshold
while abs(prev_x-x)>threshold:
prev_x = x
x = (x+number/x)/2
square_root = x
return square_root
To actually make use of guess you should keep updating it as you approximate the square root:
def sqrt(number,guess,threshold):
while abs(guess - number / guess) > threshold:
guess = (guess + number / guess) / 2
return guess

New factorial function without 0

So, the standard factorial function in python is defined as:
def factorial(x):
if x == 0:
return 1
else:
return x * factorial(x-1)
Since n! := n * (n-1) * ... * 1, we can write n! as (n+1)! / (n+1). Thus 0! = 1 and we wouldn't need that if x == 0. I tried to write that in python to but I didn't work. Can you guys help me?
Since this is a recursive function (return x * factorial(x-1)) you must have an end condition (if x == 0:).
It is true that n! == (n+1)! / (n+1) and you could change your recursive call to :
def factorial(x):
return factorial(x+1) / (x+1)
But that again would have no end condition -> endless recursion (you will calling the next (n+1)! and than the (n+2)! and so on forever (or until you'll get an exception)).
BTW, you can have the condition stop your execution at 1:
if x == 1:
return 1
You wouldn't want to use recursive function for things that are not limited, hence I suggest doing a little bit importing from the standard library
from functools import reduce
import operator
def fact(x):
if not isinstance(x, int) or x <= 0:
raise Exception("math error")
else:
return reduce(operator.mul, range(1, x + 1), 1)
print(fact("string"))
print(fact(-5))
print(fact(0))
print(fact(5))
Just realized that there is no need for a hustle like that:
def fact2(x):
if not isinstance(x, int) or x <= 0:
Exception("math error")
else:
y = 1
while x > 1:
y *= x
x -= 1
return y

python recursion (exponential)

Rapid exponentiation, I need to write an algorithm that can calculate n^b faster than n multiplications! The complexity of the algorithm will be O(logn).
I have a code, I was able to pass first 20 test (I can't see the numbers), but I can't improve the algorithm to pass last 5 tests. Any suggestions how can I improve it?
def quick_power(x, n):
if n == 0:
return 1
elif n == 1:
return x
elif n == 2:
return x * x
elif n % 2 != 0:
return x * quick_power(x, n - 1)
elif n % 2 == 0:
return quick_power(x, n // 2) * quick_power(x, n // 2)
x = int(input())
n = int(input())
print(quick_power(x, n))
Your idea is in the right direction and your code is in principle not wrong. The point is that you need to distinguish two states, even and odd
if n is even: x^n = (x^(n/2))^2
if n is odd: x^n = x*x^(n-1)
, which you actually did.
Without knowing your last 5 tests, it is hard to figure out why it failed. But you can try the following simplified code.
def quick_power(x, n):
if n == 0:
return 1
elif n % 2 == 0:
return quick_power(x, n / 2)**2
else:
return x * quick_power(x, n-1)
print(quick_power(3, 5))

Categories