I am trying to solve a problem where recursion is a must. The tasks is: Write a function that takes in an integer n and returns the highest integer in the corresponding Collatz sequence.
My solution is this:
collatz = []
def max_collatz(num):
collatz.append(num)
if num == 1:
return max(collatz)
else:
return max_collatz(num / 2) if num%2 == 0 else max_collatz((3 * num) + 1)
However, I need to find a way to solve it without using a list outside of the function. I really couldn't find a solution, is there any?
It's either the current number or the largest in the rest of the sequence.
def max_collatz(n):
if n == 1:
return 1
elif n % 2:
return max_collatz(3 * n + 1)
else:
return max(n, max_collatz(n // 2))
Related
what this code should do is you have to climb a staircase with 'n' steps. At each step, you can either climb '1' or '2' steps.
this code works with small numbers but not with big numbers, for exemple print(climbing_stairs(45)) won't work. In C there are long and double long, i was wondering if there is something similar in python.
def climbing_stairs(n):
if ( n == 0 ):
return 1
elif (n < 0):
return 0
else:
return climbing_stairs(n - 2) + climbing_stairs(n - 1)
print(climbing_stairs(2))
print(climbing_stairs(3))
print(climbing_stairs(45))
The problem with the current code is the run time complexity. This code runs in O(2^n) and it isn't feasible for larger numbers.
This problem is just a rewording of the Fibonacci numbers. What you are currently doing is to recalculate similar results repeatedly. Say, you know how many ways you can move from step 4 to n. When you don't memoize it, you will recalculate it the next time since there are different ways to reach step 4.
dp = {}
def climbing_stairs(n):
if n == 0 or n == 1:
return 1
elif n < 0:
return 0
elif n in dp:
return dp[n]
else:
dp[n] = climbing_stairs(n - 2) + climbing_stairs(n - 1)
return dp[n]
In a more pythonic way:
from functools import cache
#cache
def climbing_stairs(n):
if n == 0 or n == 1:
return 1
elif n < 0:
return 0
else:
return climbing_stairs(n - 2) + climbing_stairs(n - 1)
And there is also an elegant iterative approach to this problem that has a constant time complexity:
def climbing_stairs(n):
if n < 3: return n
first, second = 1, 2
for _ in range(1, n):
third = first+second
first, second = second, third
return second
Both the memoized recursive version and the iterative one have a linear runtime complexity, since we only calculate the each step once.
I've got a question- how do I write a function sum_even_factorials that finds the sum of the factorials of the even numbers that are less than or equal to n.
Eg:
sum_even_factorials(1)=
1
sum_even_factorials (3)=
3
sum_even_factorials (6)=
747
This is my current code:
Is there a logical error in the current code?
Is there a logical error in the current code?
To begin with, function sum_even_factorial doesn't return a value in every execution flow:
if cond1:
return val1
elif cond2:
return val2
else: # this part is missing in your code
return val3
In addition, note that when you call this function, you are not doing anything with the value that it returns:
sum_even_factorial(6)
Finally, although parts of your code are not visible in your question, I tend to guess that you cannot recursively compute the factorials of even numbers the way you did it, because the factorial of an even number n depends on the factorial of the odd number n - 1.
I think the code needs a loop. I'd write it like so:
def factorial(n):
if n == 0 or n == 1:
return 1;
else:
return n * factorial(n-1)
def sum_even_factorial(n):
current_sum = 0
while n >= 0:
if n % 2 == 0:
current_sum += factorial(n)
n -= 1
return current_sum
print(sum_even_factorial(6))
If you return tuples from the function, you can do it with one single function. See the comments in the code on how it works ...
def factorial_with_sum(n):
if n < 2:
return 1, 0 # first item of the tuple is the factorial, second item is the sum
else:
f, s = factorial_with_sum(n - 1) # calc factorial and sum for n - 1
f = f * n # factorial = n * factorial (n - 1)
if n % 2 == 0:
s = s + f # if n is even, add the current factorial to the sum
return f, s
fact, sum = factorial_with_sum(6)
print(fact)
print(sum)
You can also do it iteratively with a simple for loop as follows
def factorial_with_sum_iterative(n):
s = 0 # initialize sum
f = 1 # and factorial
for i in range(2, n + 1): # iterate from 2 to n
f = f * i # calculate factorial for current i
if i % 2 == 0:
s = s + f # if current i is even, add it to sum
return f, s
I have to write code to manually input n number and code should find that n member of sequence.n should be natural number. Formula for that sequence is
f(n)=(f(n-1))²-1
First member is 2 second 3 third 8 and every next is one less than square of number before. The code should print that n member of sequence which is inputted.
For example
In:3
Out:8
In:4
Out:63
I wrote code but it don't work
n = int(input("'input n:"))
def f(n):
if n < 0:
print('Undefined')
else:
return (f(n - 1) ** 2) - 1
print(f(n))
In recursion, you need to return a definite value for the stop index.
Here you just have to write in your code that the first value of the sequence is 2:
def f(n):
if n < 0:
raise ValueError('Undefined') # better to raise to make sure to abort
elif n == 0:
return 2
else:
return (f(n - 1) ** 2) - 1
That is enough for f(1) to return 3 and f(2) to return 8...
I am trying to find the 10001st prime using a basic logic:
1) Identify if a number is prime
2) Add it to a list if prime
3) Print the 10001st term in the list
Here is my code:
primelist=[]
import math
i=2
while True:
for x in range(2, int(math.sqrt(i))):
if i % x == 0:
continue
else:
primelist.append(i)
if len(primelist)== 10001:
break
print(primelist[-1])
Is the logic or code fundamentally wrong or inefficient?
What can I do to ameliorate/ make it work?
EDIT
I have incremented i (i+=1) and used all() to check if everything was indivisible, in response to comments
primelist=[2]
import math
i=3
while True:
for x in range(2, int(i**(1/2))):
if all(i%x!=0 for x in range(2, int(math.sqrt(i)))):
primelist.append(i)
i+=1
if len(primelist)== 10001:
break
print(primelist[-1])
Keep the algorithm/code structure the same (no optimization done), so we can easily share several language points, please see inline comments:
primelist=[]
import math
i=2
while True:
#changed to sqrt + 1, the second parameter of range is not inclusive,
#by adding 1, we make sure sqrt itself is included
for x in range(2, int(math.sqrt(i) + 1)):
if i % x == 0:
#you want break not continue, continue will try
#next possible factor, since you already figured out that this
#is not a prime, no need to keep trying
#continue
break
#a for/else block, many python users never encountered this python
#syntax. The else block is only triggered, if the for loop is naturally
#completed without running into the break statement
else:
#a little debugging, to visually confirm we generated all primes
print("adding {}".format(i))
primelist.append(i)
if len(primelist)== 11:
break
#advance to the next number, this is important,
#otherwise i will always be 2
i += 1
print(primelist[-1])
If you would like to optimize the algorithm, search online for "prime sieve".
This one should work if you want to stay with your algorithm:
import math
def is_prime(n):
for x in range(2, int(math.sqrt(n)) + 1):
if n % x == 0:
return False
return True
primelist = []
i = 2
while True:
if is_prime(i) is True:
primelist.append(i)
i += 1
if len(primelist) == 10001:
break
print(primelist[-1])
Here's a version of your code that's a bit faster, and which doesn't use much RAM. We really don't need to build a list of the primes we find. We don't use the numbers in that list to find more primes, and we're really only interested in its length. So instead of building a list we merely keep count of the primes we find.
# Include 2 in the count
count = 1
i = 3
while True:
if all(i % x for x in range(3, int(i ** 0.5) + 1, 2)):
count += 1
if count == 10001:
break
i += 2
print(i)
FWIW, here's a faster solution that uses sieving. We estimate the required size of the sieve using the prime number theorem. Wikipedia gives these bounds for p(n), the n'th prime number, which is valid for n >= 6:
log(n) + log(log(n)) - 1 < p(n) / n < log(n) + log(log(n))
We use the upper bound as the highest number in the sieve. For n < 6 we use a hard-coded list.
To save space, this sieve only holds odd numbers, so we treat the case of p(1) == 2 as a special case.
#!/usr/bin/env python3
''' Use a sieve of Eratosthenes to find nth prime
Written by PM 2Ring 2017.05.01
Sieve code derived from primes1 by Robert William Hanks
See http://stackoverflow.com/a/3035188/4014959
'''
from math import log
from sys import argv
def main():
num = int(argv[1]) if len(argv) > 1 else 10001
if num == 1:
# Handle 2 as a special case
print(1, 2)
return
elif num < 6:
# Use a pre-built table for (3, 5, 7, 11)
primes = [1, 1, 1, 1, 0, 1]
else:
# Compute upper bound from Prime number theorem
x = log(num)
hi = int(num * (x + log(x)))
print('upper bound', hi)
# Create a boolean list of odd primes in range(hi)
primes = [True] * (hi//2)
for i in range(3, 1 + int(hi**0.5), 2):
if primes[i//2]:
primes[i*i//2::i] = [False] * ((hi - i*i - 1) // (2*i) + 1)
# Count the primes until we get the nth one
k = 0
for i, b in enumerate(primes):
if b:
k += 1
if k == num:
break
print(num, 2*i+1)
if __name__ == "__main__":
main()
This code finds p(10001) = 104743 in under 0.15 seconds on my old single core 32 bit 2GHz machine running Python 3.6.0. It finds p(500000) = 7368787 in about 2.2 seconds.
I am trying to write a function that will return a list of the first n catalan numbers. This is what I have come up with so far.
def catalan_numbers(n):
if n == 0:
return 1
else:
n -= 1
return int((((2*n+2) * (2*n+1))/((n+1)*(n+2))) * catalan_numbers(n))
So far this provide me with a correct solution for a single index. So if I were to call catalan_numbers(4), 14 would be returned which is correct but exactly what I am seeking. I tried to fix this issue doing the following:
def catalan_numbers(n):
catalan = [1]
for x in range(0, n):
catalan.append(int((((2*n+2) * (2*n+1))/((n+1)*(n+2))) * catalan_numbers(n))
return catalan
But this returns:
RuntimeError: maximum recursion depth exceeded in comparison
the error is because you don't have a base case also check the following code instead of returning a one number it returns a list and concatenate the current n catalan number with the list for n-1
def catalan_numbers(n):
if n == 0:
return [1]
else:
n -= 1
t = catalan_numbers(n)
return t + [int((((2*n+2) * (2*n+1))/((n+1)*(n+2))) * t[-1])]
I would suggest iteration over recursion:
def catalan_numbers(N):
C = [1]
for n in range(1, N):
C.append((4*n - 2) * C[-1] // (n + 1))
return C