Replace simple while loop by recursion - python

If I have an simple function (pseudocode) like
fun(a, b):
x = a
i = 0
while i < b do
x = x + a
i ++
return x
Can I replace the while loop in this function by a recursion?

Something like:
fun (a, b, i):
if i >= b:
return 1
else:
return a + fun(a, b, i + 1)

Without using an extra parameter you can try:
def f(a, b):
if b <= 1:
return a
else:
return a + f(a, b - 1)
Note: This will only work for b >= 1.

def fun(x, y):
if y != 0:
for i in fun(x, y-1):
yield x + i
yield 0

Related

Recursive function that returns the remainder

I am instructed to define a recursive function in Python that finds the remainder of n divided by b with the condition to not use the "/" ,"%" or "//" operator. I have defined the following function, which works fine for positive numbers. Is there a better way to do this using recursion and simple conditions.
def division(n, b, q = 1):
"""
parameters : a et b (integers)
returns: the remainder of a and b
pre-requisites : q = 1
"""
if n <= 0 or n < b:
if n == 0:
print("Your division has no remainder.")
elif n in range(0,5):
print("Your remainder is", n)
return 0
else:
return division(n - b, b, q) + q
print(division(274,5))
I believe your teacher was probably only trying to go for remainders without quotients.
def division(n, b):
if n < b:
return n
return division(n - b, b)
print(division(274, 5))
However, since you brought it up, you can do it with the quotient, without having to start with a 1 for the default.
def division(n, b, q = 0):
if n < b:
return n, q
return division(n - b, b, q + 1)
print(division(274, 5))
Main takeaways, you do not need to check n for range (0,5).
What about
def remainder(n, q):
if(n < q):
return n
return remainder(n - q, q)
print(remainder(274, 5)) # will return: 4
print(remainder(275, 5)) # will return: 0
print(remainder(123, 3)) # will return: 0
much shorter ...

How to append a while function to list?

How does one append the output of a while function into a list? For example:
fib = []
def FIB():
a,b = 0,1
while a < 100:
fib.append(a)
a, b = b, a + b
print(fib)
I am expecting:
[0,1,1,2,3,5,8,13,21,34,55,89]
But I receive:
[]
you need to return fib, so you can print it. You also need to call your function correctly.
fib = []
def FIB():
a,b = 0,1
while a < 100:
fib.append(a)
a, b = b, a + b
return fib
print(FIB())
fib = []
def FIB(fib):
a,b = 0,1
while a < 100:
fib.append(a)
a, b = b, a + b
return fib
print(FIB(fib))

Generate 2D array in different ways

This is a DP problem, which I solve using 2D array in python.
The problem is the way I generate the 2D array.
Standard solution:
def getFloor(F, c, d):
if d == 0 or c == 0:
return 0
if c == 1:
return d
if F[c][d] == -1:
F[c][d] = getFloor(F, c, d-1) + getFloor(F, c-1, d-1) + 1
return F[c][d]
def getMaxFloor(c,d):
F = [[-1] * (d + 1) for i in range(c + 1)]
ans = getFloor(F, c, d)
return ans
print(getMaxFloor(3,4)) #prints 14
My code:
def getFloor(F, c, d):
if d == 0 or c == 0:
return 0
if c == 1:
return d
if F[c][d] == -1:
F[c][d] = getFloor(F, c, d-1) + getFloor(F, c-1, d-1) + 1
return F[c][d]
def getMaxFloor(c,d):
F = [[-1] * (d + 1)] * (c+1)
ans = getFloor(F, c, d)
return ans
print(getMaxFloor(3,4)) #prints 15, instead of the correct answer 14
I check both of the arrays F when both are initialized, which returns true.
What's the problem?
I'm guessing the problem is that when you multiply it, you are just creating duplicates or references to the same list element. So if you change one, you change the other. Whereas if you use the for loop, it creates separate unlinked instances so that when one gets changed it does not affect the other. (You would have to do a lot of tracing back, etc. to figure out exactly why the answer is off by exactly 1.) But this is really the only difference between the codes so it must be the problem. Hope this helps.
For example:
l = [1,2,3]
a = [2]
l.append(a)
a[0] = 4
print l
>>>[1, 2, 3, [4]]
Notice that the last element in l is [4] instead of [2].

Tail recursion to loop

I as working on a program that given a and b, computes the last 5 digits of a^b. I currently have it working as long as b is sufficiently low, but if b is large (>1000) this will crush the stack. Is there a way I can make this an iterative function? I have tried converting to iterative, but I can't figure it out.
def pow_mod(a,b):
if b == 0:
return 1
elif b == 2:
return a*a % 10000
return ((b%2*(a-1) + 1) * pow_mod(a,b//2)**2) % 10000
In order to do this computation, iteratively, you start with an answer=a, and then square it repeatedly (and multiply by a if b is odd). To exit the loop, divide b by 2 each time, and check for when b>1.
def pow_mod(a,b):
if b == 0:
return 1
c = 1;
while b > 1:
if b % 2:
c *= a
a *= a
b //= 2
a %= 10000
c %= 10000
return a * c % 10000
Use a while loop instead of recursion, to adjust b the same way that you do in the recursive call.
def pow_mod(a, b):
result = 1
while b > 0:
result = (b%2*(a-1) + 1) * result**2) % 10000
b = b//2
return result
The trick is to store the result in a temporary variable and then pass it to each function call.
lst = []
while b:
lst.insert(0, b)
b = b//2
def _pow_mod(a, b, answer):
if b == 2:
return a*a % 10000;
else:
return ((b%2*(a-1) + 1) * answer **2) % 10000
answer = 1 # b = 0 case
for b in lst:
answer = _pow_mod(a, b, answer)
Complete Code:
# Original recursive solution
def pow_mod_orig(a, b):
if b == 0:
return 1
elif b == 2:
return a*a % 10000
return ((b%2*(a-1) + 1) * pow_mod_orig(a,b//2)**2) % 10000
# Iterative solution
def pow_mod(a, b):
lst = []
while b:
lst.insert(0, b)
b = b//2
def _pow_mod(a, b, answer):
if b == 2:
return a*a % 10000;
else:
return ((b%2*(a-1) + 1) * answer **2) % 10000
answer = 1 # b = 0 case
for b in lst:
answer = _pow_mod(a, b, answer)
return answer
for i in range(1000):
assert(pow_mod_orig(3, i) == pow_mod(3, i))

Harmonic series in python

Does anyone know how to code the Harmonic Series in python?
H(n) = 1 + 1/2 + 1/3 + ... + 1/n
Note: We're not allowed to import from predefined modules. The output must be the numerator and the denominator of the answer in fraction form (lowest terms).
so here's my code for this harmonic series.
n = input("Enter n:")
def harmonic(n):
a=1
b=1
for d in range(2, n+1):
a = a*d+b
b = b*d
return (a,b)
x == max(a,b)%min(a, b)
if x == 0:
y=min(a,b)
return y
else:
y=min(a,b)/x
return y
a=a/y
b=b/y
return (a,b)
print harmonic(n)
what's wrong? Whatever I input, the output is always (3,2)
I have to check your attempt twice - and inserted a simple gcd (in the middle of the your original code)
n = input("Enter n:")
def harmonic(n): #original harmonic series
a=1
b=1
for d in range(2, n+1):
a = a*d+b
b = b*d
return(a,b)
def harmonic_lt(n): #_lt: harmonic series with lowest terms
#not pythonic, but simple
a=1
b=1
for d in range(2, n+1):
a = a*d+b
b = b*d
y=a
x=b
while x > 0:
re = y % x
y = x
x = re
a=a/y
b=b/y
return(a,b)
print harmonic(n)
print harmonic_lt(n)
As others pointed out, you are returning when d = 2 i.e. (1 + 1/2), it should be outside of the for loop.
Here's a code I wrote for doing the same:
#!Python2.7
def gcd(a, b):
if b: return gcd(b, a%b)
return a
def lcm(a, b):
return a*b/gcd(a, b)
def start():
n = int(raw_input())
ans = reduce(lambda x, y: (x[0]*lcm(x[1],y[1])/x[1]+y[0]*lcm(x[1],y[1])/y[1], lcm(x[1],y[1])),[(1,x) for x in xrange(1,n+1)])
_gcd = gcd(ans[0], ans[1])
print (ans[0]/_gcd, ans[1]/_gcd)
start()
If you want to avoid using reduce, lamda and list comprehensions:
#!Python2.7
def gcd(a, b):
if b: return gcd(b, a%b)
return a
def lcm(a, b):
assert a != 0
assert b != 0
return a*b/gcd(a, b)
def next(x, y):
lcmxy = lcm(x[1], y[1])
return (x[0]*lcmxy/x[1]+y[0]*lcmxy/y[1], lcmxy)
def start():
n = int(raw_input())
curr = (1,1)
for x in xrange(2,n+1):
curr = next(curr, (1,x))
_gcd = gcd(curr[0], curr[1])
print (curr[0]/_gcd, curr[1]/_gcd)
start()
You can find the denominator by finding the lowest common multiple of the numbers 1..n.
The nominator will then be the sum of all values denominator/x with x being all values from 1..n.
Here's some code:
def gcd(a, b):
"""Return greatest common divisor using Euclid's Algorithm."""
while b:
a, b = b, a % b
return a
def lcm(a, b):
"""Return lowest common multiple."""
return a * b // gcd(a, b)
def lcmm(args):
"""Return lcm of args."""
return reduce(lcm, args)
def harmonic(n):
lowest_common_multiple = lcmm(range(1,n))
nominator = sum([lowest_common_multiple/i for i in range(1,n)])
greatest_common_denominator = gcd(lowest_common_multiple, nominator)
return nominator/greatest_common_denominator, lowest_common_multiple/greatest_common_denominator
print harmonic(7)
print harmonic(10)
print harmonic(20)
Harmonic series:
1/1 + 1/2 + ... + 1/n == (n!/1 + n!/2 + ... + n!/n)/n!
therefore you can do:
nom = reduce(lambda s, x: s*x, xrange(1, n+1),1) # n!
denom = sum([nom / x for x in xrange(1, n+1)])
Then you need to do gcd-reduction on nom and denom.
Use the version from Thorsten Kranz.
Note that this way only one call to gcd is needed!
Example:
def gcd(a, b):
while b:
a, b = b, a % b
return a
def harmonic(n):
nom = reduce(lambda s, x: s*x, xrange(1,n+1), 1) # n!
denom = sum([nom / x for x in xrange(1, n+1)])
f = gcd(denom, nom)
return (denom / f), (nom / f)
print harmonic(10)
print harmonic(20)
(7381, 2520)
(55835135, 15519504)
You always return (a,b) at the first iteration. – Scharron"
Return always ends a function. If you return (a,b), the rest of the code is unreachable

Categories

Resources