Problem: Return the number of nodes in the linked list.
I am learning recursion recently. I know how to use iteration to solve this problem but I am stick by the recursion way. The following is my code and it always return 1 instead of the real count of the linked list. I cannot figure out the problem and hope someone can help me. How can I fix the problem?
def numberOfNodes(head):
total_node = 0
return __helper(total_node, head)
def __helper(total_node, head):
if not head:
return total_node += 1
__helper(total_node, head.next)
return total_node
Recursion is a poor choice for this sort of thing (adds overhead and risks blowing the call stack for no good reason), but if you do use it for educational purposes, it's easiest to pass the total up the call stack, not down:
def linked_list_len(head):
return linked_list_len(head.next) + 1 if head else 0
Basically, add 1 per frame where the head node exists, then call the function again with the next node. The base case is when head is None.
In some languages that offer tail call optimization, you can avoid the + 1 work that happens to the variable returned by the child recursive call per frame. This allows the compiler or interpreter to convert recursion to a loop, avoiding stack overflows. The code would look like (similar to your approach, with the difference that the + 1 is added in the recursive call):
def linked_list_len(head, total=0):
return linked_list_len(head.next, total + 1) if head else total
But Python doesn't support TCO so you may as well write it the simpler way shown above.
I've had the following assignment: Given a list of n integers, each integer in the list is unique and larger than 0. I am also given a number K - which is an integer larger than 0.
List slicing of any kind is not allowed
I need to check whether there is a subset that sums up to K.
e.g: for the list [1,4,8], and k=5, I return True, because we have the subset {1,4}.
Now I need to implement this using a recursion:
So I did, however I needed to implement memoization:
And I wonder what is the difference between those functions' code:
I mean, both seem to implement memoization, however the second should work better but it doesn't. I'd really appreciate some help :)
def subsetsum_mem(L, k):
'''
fill-in your code below here according to the instructions
'''
sum_dict={}
return s_rec_mem(L,0,k,sum_dict)
def s_rec_mem(L, i, k, d):
'''
fill-in your code below here according to the instructions
'''
if(k==0):
return True
elif(k<0 or i==len(L)):
return False
else:
if k not in d:
res_k=s_rec_mem(L,i+1,k-L[i],d) or s_rec_mem(L,i+1,k,d)
d[k]=res_k
return res_k
def subsetsum_mem2(L, k):
'''
fill-in your code below here according to the instructions
'''
sum_dict={}
return s_rec_mem2(L,0,k,sum_dict)
def s_rec_mem2(L, i, k, d):
'''
fill-in your code below here according to the instructions
'''
if(k==0):
return True
elif(k<0 or i==len(L)):
return False
else:
if k not in d:
res_k=s_rec_mem2(L,i+1,k-L[i],d) or s_rec_mem2(L,i+1,k,d)
d[k]=res_k
return res_k
else:
return d[k]
You have two problems with your memoization.
First, you're using just k as the cache key. But the function does different things for different values of i, and you're ignoring i in the cache, so you're going to end up returning the value from L, 9, 1, d for L, 1, 1, d.
Second, only in s_rec_mem, you never return d[k]; if it's present, you just fall off the end and return None (which is falsey).
So, the second one does come closer to working—but it still doesn't actually work.
You could fix it like this:
def s_rec_mem2(L, i, k, d):
'''
fill-in your code below here according to the instructions
'''
if(k==0):
return True
elif(k<0 or i==len(L)):
return False
else:
if (i, k) not in d:
res_k=s_rec_mem2(L,i+1,k-L[i],d) or s_rec_mem2(L,i+1,k,d)
d[i, k]=res_k
return res_k
else:
return d[i, k]
… or by just using lru_cache, either by passing down tuple(L) instead of L (because tuples, unlike lists, can be hashed as keys, and your recursive function doesn't care what kind of sequence it gets), or by making it a local function that sees L via closure instead of getting passed it as a parameter.
Finally, from a quick glance at your code:
It looks like you're only ever going to evaluate s_rec_mem at most twice on each set of arguments (assuming you correctly cache on i, k rather than just k), which means memoization can only provide a 2x constant speedup at best. To get any more than that, you need to rethink your caching or your algorithm.
You're only memoizing within each separate top-level run, but switching to lru_cache on tuple(L), i, k means you're memoizing across all runs until you restart the program (or REPL session)—so the first test may take a long time, but subsequent runs on the same L (even with a different k) could benefit from previous caching.
You seem to be trying to solve a minor variation of the subset sum problem. That problem in the general case is provably NP-complete, which means it's guaranteed to take exponential time. And your variation seems to be if anything harder than the standard problem, not easier. If so, not only is your constant-factor speedup not going to have much benefit, there's really nothing you can do that will do better. In real life, people who solve equivalent problems usually use either optimization (e.g., via dynamic programming) or approximation to within an arbitrary specified limit, both of which allow for polynomial (or at least pseudo-polynomial) solutions in most cases, but can't solve all cases. Or, alternatively, there are subclasses of inputs for which you can solve the problem in polynomial time, and if you're lucky, you can prove your inputs fall within one of those subclasses. If I've guessed right on what you're doing, and you want to pursue any of those three options, you'll need to do a bit of research. (Maybe Wikipedia is good enough, or maybe there are good answers here or on the compsci or math SE sites to get you started.)
This question already has answers here:
Recursion or Iteration?
(31 answers)
Closed 5 years ago.
I am relatively new to python and have recently learned about recursion. When tasked to find the factorial of a number, I used this:
def factorial(n):
product = 1
for z in xrange(1,n+1):
product *= z
return product
if __name__ == "__main__":
n = int(raw_input().strip())
result = factorial(n)
print result
Then, because the task was to use recursion, I created a solution that used recursion:
def factorial(n):
if n == 1:
current = 1
else:
current = n*(factorial(n-1))
return current
if __name__ == "__main__":
n = int(raw_input().strip())
result = factorial(n)
print result
Both seem to produce the same result. My question is why would I ever use recursion, if I could use a for loop instead? Are there situations where I cannot just create for loops instead of using recursion?
For every solution that you found with recursion there are a solution iterative, because you can for example simulate the recursion using an stack.
The example of Factorial use a type of recursion named Tail Recursion an this cases have an easy way to implement iterative, but in this case recursion solution is more similar to the mathematical definition. However there are other problems that found an iterative solution is difficult and is more powerful and more expressive use recursive solution. For example the problem of Tower of Hanoi see this question for more informationTower of Hanoi: Recursive Algorithm, the solution of this problem iterative is very tedious and finally have to simulate a recursion.
There are problems like Fibonacci sequence that the definition is recursive an is easy to generate a solution recursive
def fibonacci(n):
if ((n==1) or (n==2)):
return 1
else (n>2):
return fibonacci(n-2) + fibonacci(n-1)
This solution is straight forward, but calculate many times unnecessarily the fibonacci of n-2 see the image bellow to better understanding the fibonacci(7)
So you can see the recursion like syntactic sugar some time, but depends of what you want, you need to decide if use or no. When you program in Low-level programming language the recursion is not used, when you program a microprocessor is a big error, but on others case is better use a recursive solutions for better understanding of your code.
hope this help, but you need go deep reading books.
This recursive factorial calculator runs fine all the way up to an input of 994 when I recieve this error: "RecursionError: maximum recursion depth exceeded in comparison". Can someone please explain what is meant by this? How can there be a maximum amount of recursions? Thanks in advance.
def factorial(x):
if( x == 0):
return 1
else:
return x * factorial(x - 1)
while True:
u_input = input("")
print(factorial(int(u_input)))
def calc_factorial(num):
num-=1
fact_total = 1
while num > 0:
fact_total *= num
num-=1
return(fact_total)
EDIT:
I understand that recursion is re-using a function from within that function as a loop but I do not understand what recursion depth is and would like that explained. I could not tell from the answers to the other question. Apologies for the confusion.
Recursive calls are just like any other function calls, and function calls use memory to keep track of the state inside each function. You will notice that you get a very long traceback showing all the nested function calls that are on the stack. Since memory is finite, recursion depth (the number of nested function calls) is inherently limited even without python's enforced limit.
The error means what it says: Python limits the depth of how many recursive calls you can make. The default is 1000, which was chosen as a number that means you most likely have infinite recursion somewhere. Since no computer can keep track of an infinite amount of recursive calls (and such a program would never finish anyway), halting with this error message is seen as preferable to recurring as deeply as the computer can handle, which eventually results in a stack overflow.
You can change this limit if you wish with sys.setrecursionlimit, but the best way to avoid this issue is to change your program to work iteratively instead of recursively. Fortunately, this is easy for a factorial calculation:
def factorial(x):
result = 1
for num in range(1, x+1):
result *= num
return result
There are built in Function with Math library, It is improved algorithm to get the value of factorial quickly, So when we are writing the recursive algorithm to get the value for factorial, there will be a recursive limit. So If we use the built in library, then we can escape from that problem.
import math
math.factorial(5)
Answer : 120
So here is my code for min-heap. It's a part of my homework:
def heapify(i):
global end,a
l=2*i+1
if l>end:
return None
r=2*i+2
minarg=i
if a[i]>a[l]:
minarg=l
if r<=end:
if a[minarg]>a[r]: minarg=r
if a[i]==a[minarg]:
return None
else:
a[i],a[minarg]=a[minarg], a[i]
heapify(minarg)
def buildHeap(start):
global end,a
if start*2+1>end:
return None
buildHeap(start*2+1)
buildHeap(start*2+2)
heapify(start)
It should be working, but I get time limit exceeded for large testcases. Am I doing something wrong?
Function calls in Python take time, recursion takes space.
To save the time of a recursion one usually transforms it into a loop. This usually requires to use a specialized "memory management" of the date to work on to safe space. You did that already (with... ehem... global variables) using an array/list.
If that is your homework, go ahead -- doable, but non-trivial.