Why is my solution on LeetCode not working (recursion, python)? - python

class Solution:
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
if n == 1:
return 1
if n == 2:
return 2
else:
return self.climbStairs(n - 1) + self.climbStairs(n - 2)
My solution however is not working on Leetcode. Do you know why this is? Thank you so much!
I am trying to solve fibonacci sequence

You've chosen a poor algorithm. It's not that it's recursive, just horribly inefficient. Here's a more efficient recursive approach:
def climbStairs(self, n, res=1, nxt=1):
if n == 0:
return res
return self.climbStairs(n - 1, nxt, res + nxt)
This runs much faster than your code and can go a lot higher before getting a stack overflow. But it will eventually get a stack overflow. We might do better adding memoization but ultimately, a simple iterative solution would be easier:
def climbStairs(self, n): # doesn't use 'self', could be class method
if 0 <= n <= 1:
return 1
a = b = 1
for _ in range(n - 1):
a, b = b, a + b
return b

Your solution looks good but it's inefficient. You don't have to address if n==2 part. Keep it simple, like this:
class Solution:
def climbStairs(self, n: int) -> int:
if n == 0 or n == 1:
return 1
return self.climbStairs(n-1) + self.climbStairs(n-2)

Related

#lru_cache decorator: How does it use its previous value to speed it up?

Doing some leetcode questions and I came across this solution:
class Solution:
def isValidPalindrome(self, s: str, k: int) -> bool:
#lru_cache(None)
def helper(lo, hi, k):
while lo < hi:
if s[lo] == s[hi]:
lo, hi = lo + 1, hi - 1
elif k > 0:
return helper(lo, hi - 1, k - 1) or helper(lo + 1, hi, k - 1)
else:
return False
return True
return helper(0, len(s) - 1, k)
Well clearly, #lru_cache speeds up the process as this solution is accepted but without #lru_cache, I get a time limit exceeded. I'm really confused as to how this speeds the process up. From this code, I do not see how it uses stored values as the lo and hi are unique every time!

Python: Create function without recursion

I would like to create this function without recursion.
def fib2(n: int) -> int:
if(n <= 0): return 0
if(n <= 2): return n
return ((fib2(n-1) * fib2(n-2)) - fib2(n-3))
Can anyone help me or explain how to solve this?
One rather concise and Pythonic way to do it without any extra space requirements:
def fib2(n: int) -> int:
a, b, c = 0, 1, 2
for _ in range(n):
a, b, c = b, c, (c * b) - a
return a
You need to keep track of three values for the calculation and just keep rotating through them.
Find all the fib2 results from 1 to nn.
def fib2(nn: int) -> int:
mem = {
0: 0, # first if
1: 1, # second if
2: 2 # second if
}
# now find all the fib2 results from 3 to nn
kk = 3
while ( kk <= nn ) :
mem[kk] = mem[kk-1] * mem[kk-2] - mem[kk-3]
kk++;
return mem[nn]

Recursive to iterative using a systematic method [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I've started reading the book Systematic Program Design: From Clarity to Efficiency few days ago. Chapter 4 talks about a systematic method to convert any recursive algorithm into its counterpart iterative. It seems this is a really powerful general method but I'm struggling quite a lot to understand how it works.
After reading a few articles talking about recursion removal using custom stacks, it feels like this proposed method would produce a much more readable, optimized and compact output.
Recursive algorithms in Python where I want to apply the method
#NS: lcs and knap are using implicit variables (i.e.: defined globally), so they won't
#work directly
# n>=0
def fac(n):
if n==0:
return 1
else:
return n*fac(n-1)
# n>=0
def fib(n):
if n==0:
return 0
elif n==1:
return 1
else:
return fib(n-1)+fib(n-2)
# k>=0, k<=n
def bin(n,k):
if k==0 or k==n:
return 1
else:
return bin(n-1,k-1)+bin(n-1,k)
# i>=0, j>=0
def lcs(i,j):
if i==0 or j==0:
return 0
elif x[i]==y[j]:
return lcs(i-1,j-1)+1
else:
return max(lcs(i,j-1),lcs(i-1,j))
# i>=0, u>=0, for all i in 0..n-1 w[i]>0
def knap(i,u):
if i==0 or u==0:
return 0
elif w[i]>u:
return knap(i-1,u)
else:
return max(v[i]+knap(i-1,u-w[i]), knap(i-1,u))
# i>=0, n>=0
def ack(i,n):
if i==0:
return n+1
elif n==0:
return ack(i-1,1)
else:
return ack(i-1,ack(i,n-1))
Step Iterate: Determine minimum increments, transform recursion into iteration
The Section 4.2.1 the book talks about determining the appropriate increment:
1) All possible recursive calls
fact(n) => {n-1}
fib(n) => {fib(n-1), fib(n-2)}
bin(n,k) => {bin(n-1,k-1),bin(n-1,k)}
lcs(i,j) => {lcs(i-1,j-1),lcs(i,j-1),lcs(i-1,j)}
knap(i,u) => {knap(i-1,u),knap(i-1,u-w[i])}
ack(i,n) => {ack(i-1,1),ack(i-1,ack(i,n-1)), ack(i,n-1)}
2) Decrement operation
fact(n) => n-1
fib(n) => n-1
bin(n,k) => [n-1,k]
lcs(i,j) => [i-1,j]
knap(i,u) => [i-1,u]
ack(i,n) => [i,n-1]
3) Minimum increment operation
fact(n) => next(n) = n+1
fib(n) => next(n) = n+1
bin(n,k) => next(n,k) = [n+1,k]
lcs(i,j) => next(i,j) = [i+1,j]
knap(i,u) => next(i,u) = [i+1,u]
ack(i,n) => next(i,n) = [i,n+1]
Section 4.2.2 talks about forming the optimized program:
Recursive
---------
def fExtOpt(x):
if base_cond(x) then fExt0(x ) -- Base case
else let rExt := fExtOpt(prev(x)) in -- Recursion
f Ext’(prev(x),rExt) -- Incremental computation
Iterative
---------
def fExtOpt(x):
if base_cond(x): return fExt0(x) -- Base case
x1 := init_arg; rExt := fExt0(x1) -- Initialization
while x1 != x: -- Iteration
x1 := next(x1); rExt := fExt’(prev(x1),rExt) -- Incremental comp
return rExt
How do I create {fibExtOpt,binExtOpt,lcsExtOpt,knapExtOpt,ackExtOpt} in Python?
Additional material about this topic can be found in one of the papers of the main author of the method, Y. Annie Liu, Professor.
So, to restate the question. We have a function f, in our case fac.
def fac(n):
if n==0:
return 1
else:
return n*fac(n-1)
It is implemented recursively. We want to implement a function facOpt that does the same thing but iteratively. fac is written almost in the form we need. Let us rewrite it just a bit:
def fac_(n, r):
return (n+1)*r
def fac(n):
if n==0:
return 1
else:
r = fac(n-1)
return fac_(n-1, r)
This is exactly the recursive definition from section 4.2. Now we need to rewrite it iteratively:
def facOpt(n):
if n==0:
return 1
x = 1
r = 1
while x != n:
x = x + 1
r = fac_(x-1, r)
return r
This is exactly the iterative definition from section 4.2. Note that facOpt does not call itself anywhere. Now, this is neither the most clear nor the most pythonic way of writing down this algorithm -- this is just a way to transform one algorithm to another. We can implement the same algorithm differently, e.g. like that:
def facOpt(n):
r = 1
for x in range(1, n+1):
r *= x
return r
Things get more interesting when we consider more complicated functions. Let us write fibObt where fib is :
def fib(n):
if n==0:
return 0
elif n==1:
return 1
else:
return fib(n-1) + fib(n-2)
fib calls itself two times, but the recursive pattern from the book allows only a single call. That is why we need to extend the function to returning not one, but two values. Fully reformated, fib looks like this:
def fibExt_(n, rExt):
return rExt[0] + rExt[1], rExt[0]
def fibExt(n):
if n == 0:
return 0, 0
elif n == 1:
return 1, 0
else:
rExt = fibExt(n-1)
return fibExt_(n-1, rExt)
def fib(n):
return fibExt(n)[0]
You may notice that the first argument to fibExt_ is never used. I just added it to follow the proposed structure exactly.
Now, it is again easy to turn fib into an iterative version:
def fibExtOpt(n):
if n == 0:
return 0, 0
if n == 1:
return 1, 0
x = 2
rExt = 1, 1
while x != n:
x = x + 1
rExt = fibExt_(x-1, rExt)
return rExt
def fibOpt(n):
return fibExtOpt(n)[0]
Again, the new version does not call itself. And again one can streamline it to this, for example:
def fibOpt(n):
if n < 2:
return n
a, b = 1, 1
for i in range(n-2):
a, b = b, a+b
return b
The next function to translate to iterative version is bin:
def bin(n,k):
if k == 0 or k == n:
return 1
else:
return bin(n-1,k-1) + bin(n-1,k)
Now neither x nor r can be just numbers. The index (x) has two components, and the cache (r) has to be even larger. One (not quite so optimal) way would be to return the whole previous row of the Pascal triangle:
def binExt_(r):
return [a + b for a,b in zip([0] + r, r + [0])]
def binExt(n):
if n == 0:
return [1]
else:
r = binExt(n-1)
return binExt_(r)
def bin(n, k):
return binExt(n)[k]
I have't followed the pattern so strictly here and removed several useless variables. It is still possible to translate to an iterative version directly:
def binExtOpt(n):
if n == 0:
return [1]
x = 1
r = [1, 1]
while x != n:
r = binExt_(r)
x += 1
return r
def binOpt(n, k):
return binExtOpt(n)[k]
For completeness, here is an optimized solution that caches only part of the row:
def binExt_(n, k_from, k_to, r):
if k_from == 0 and k_to == n:
return [a + b for a, b in zip([0] + r, r + [0])]
elif k_from == 0:
return [a + b for a, b in zip([0] + r[:-1], r)]
elif k_to == n:
return [a + b for a, b in zip(r, r[1:] + [0])]
else:
return [a + b for a, b in zip(r[:-1], r[1:])]
def binExt(n, k_from, k_to):
if n == 0:
return [1]
else:
r = binExt(n-1, max(0, k_from-1), min(n-1, k_to+1) )
return binExt_(n, k_from, k_to, r)
def bin(n, k):
return binExt(n, k, k)[0]
def binExtOpt(n, k_from, k_to):
if n == 0:
return [1]
ks = [(k_from, k_to)]
for i in range(1,n):
ks.append((max(0, ks[-1][0]-1), min(n-i, ks[-1][1]+1)))
x = 0
r = [1]
while x != n:
x += 1
r = binExt_(x, *ks[n-x], r)
return r
def binOpt(n, k):
return binExtOpt(n, k, k)[0]
In the end, the most difficult task is not switching from recursive to iterative implementation, but to have a recursive implementation that follows the required pattern. So the real question is how to create fibExt', not fibExtOpt.

Project Euler #15 in Python

I am newbie in Python. I'm stuck on doing Problem 15 in Project-Euler in reasonable time. The problem in memoize func. Without memoize all working good, but only for small grids. I've tried to use Memoization, but result of such code is "1" for All grids.
def memoize(f): #memoization
memo = {}
def helper(x):
if x not in memo:
memo[x] = f(x)
return memo[x]
return helper
#memoize
def search(node):
global route
if node[0] >= k and node[1] >= k:
route += 1
return route
else:
if node[0] < k + 1 and node[1] < k + 1:
search((node[0] + 1, node[1]))
search((node[0], node[1] + 1))
return route
k = 2 #grid size
route = 0
print(search((0, 0)))
If commenting out code to disable memoize func:
##memoize
all works, but to slow for big grids. What am i doing wrong? Help to debbug. Thx a lot!
Update1:
Thank for your help, I've found answer too:
def memoize(f):
memo = {}
def helper(x):
if x not in memo:
memo[x] = f(x)
return memo[x]
return helper
#memoize
def search(node):
n = 0
if node[0] == k and node[1] == k:
return 1
if node[0] < k+1 and node[1] < k+1:
n += search((node[0] + 1, node[1]))
n += search((node[0], node[1] + 1))
return n
k = 20
print(search((0, 0)))
Problem was not in memoize func as i thought before. Problem was in 'search' function. Whithout globals it wroiking right i wished. Thx for comments, they was really usefull.
Your memoization function is fine, at least for this problem. For the more general case, I'd use this:
def memoize(f):
f.cache = {} # - one cache for each function
def _f(*args, **kwargs): # - works with arbitrary arguments
if args not in f.cache: # as long as those are hashable
f.cache[args] = f(*args, **kwargs)
return f.cache[args]
return _f
The actual problem -- as pointed out by Kevin in the comments -- is that memoization only works if the function does not work via side effects. While your function does return the result, you do not use this in the recursive calculation, but just rely on incrementing the global counter variable. When you get an earlier result via memoization, that counter is not increased any further, and you do not use the returned value, either.
Change your function to sum up the results of the recursive calls, then it will work.
You can also simplify your code somewhat. Particularly, the if check before the recursive call is not necessary, since you check for >= k anyway, but then you should check whether the x component or the y component is >= k, not both; once either has hit k, there's just one more route to the goal. Also, you could try to count down to 0 instead of up to k so the code does not need k anymore.
#memoize
def search(node):
x, y = node
if x <= 0 or y <= 0:
return 1
return search((x - 1, y)) + search((x, y - 1))
print(search((20, 20)))
Try this code. It works fast even with grids over 1000x1000! Not nessesarily square.
But I didn't know about memoization yet...
import time
def e15():
x=int(input("Enter X of grid: "))
y=int(input("Enter Y of grid: "))
start = time.time()
lst=list(range(1,x+2))
while lst[1]!=y+1:
i=0
for n in lst[1:]:
i+=1
lst[i]=n+lst[i-1]
print(f"There are {lst[-1]} routes in {x}x{y} grid!")
end = time.time() - start
print("Runtime =", end)
e15()
This problem can be solved in O(1) time by using the code below:
from math import factorial as f
n, m = map(int, input("Enter dimensions (separate by space)?").split())
print ("Routes through a", n, "x", m, "grid", f(n+m) // f(n) // f(m))
Here's a link for a proof of the equation:
Project Euler Problem 15 Solution

Python recursive program

I'm relatively newcomer on programming as I'm educated a mathematician and have no experience on Python. I would like to know how to solve this problem in Python which appeared as I was studying one maths problem on my own:
Program asks a positive integer m. If m is of the form 2^n-1 it returns T(m)=n*2^{n-1}. Otherwise it writes m to the form 2^n+x, where -1 < x < 2^n, and returns T(m)=T(2^n-1)+x+1+T(x). Finally it outputs the answer.
I thought this was a neat problem so I attempted a solution. As far as I can tell, this satisfies the parameters in the original question.
#!/usr/bin/python
import math
def calculate(m: int) -> int:
"""
>>> calculate(10)
20
>>> calculate(100)
329
>>> calculate(1.2)
>>> calculate(-1)
"""
if (m <= 0 or math.modf(m)[0] != 0):
return None
n, x = decompose(m + 1)
if (x == 0):
return n * 2**(n - 1)
else:
return calculate(2**n - 1) + x + 1 + calculate(x)
def decompose(m: int) -> (int, int):
"""
Returns two numbers (n, x), where
m = 2**n + x and -1 < x < 2^n
"""
n = int(math.log(m, 2))
return (n, m - 2**n)
if __name__ == "__main__":
import doctest
doctest.testmod(verbose = True)
Assuming the numbers included in the calculate function's unit tests are the correct results for the problem, this solution should be accurate. Feedback is most welcome, of course.

Categories

Resources