So I wrote a code which is supposed to get the parent of a given node in a tree. Here is the pseudo code. Starting from the root,
def parent(self, child):
if right child exists:
if the right child == child:
return self
else: self.right.parent(child)
if left child exists:
if the left child == child:
print('f')
return self
else: self.left._get_parent(node)
I keep coming across this problem over and over and over again.
For the if the left child == child: statement, the function DOES enter the if statement if it finds that either the left child == child or the right child == child.
However, the return statement does not execute this. I know this because when I wrote the if the left child == child: and wrote print('f') after it, it did print f, however, it did not return self. Does anyone know why and can anyone give a solution as to how to fix this problem?
Additionally, does anyone know how to return two statements at once NOT as tuples or lists?
For example, if I want to return 1 and 2,
def x(n):
return 1, 2
This would return (1, 2).. is there any way for it to not return it as a tuple? And just to return it normally. I'm asking this because when it comes to recursion, I want to call the same function on 1 AS WELL AS 2, and not on the tuple (1, 2).
Your code discards the return values of recursive calls in the else: branches. You need more return statements:
if right child exists:
if the right child == child:
return self
else:
return self.right.parent(child)
if left child exists:
if the left child == child:
print('f')
return self
else:
return self.left._get_parent(node)
In Python, the expression 1, 2 creates a tuple, and that is the canonical way to return multiple values from functions. That is how multiple value returns work, by returning a tuple.
Simply unpack the returned value:
def foo():
return 1, 2
value1, value2 = foo()
or use indexing:
values = foo()
values[0], values[1]
Related
I'm new to the concept of recursion, had never practiced this magic in my coding experience. Something I'm really confused about Python recursion is the use of "return". To be more specific, I don't quite understand when to use return in some situations. I've seen cases where the return is used before recursion, and cases return is not needed at all.
For example:
A Leetcode Question: "Given the root node of a binary search tree (BST) and a value. You need to find the node in the BST that the node's value equals the given value. Return the subtree rooted with that node. If such node doesn't exist, you should return NULL."
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def searchBST(self, root, val):
"""
:type root: TreeNode
:type val: int
:rtype: TreeNode
"""
if root == None:
return root
if root.val == val:
return root
elif root.val > val:
return self.searchBST(root.left,val)
else:
return self.searchBST(root.right,val)
Why do I need to return "self.searchBST(root.left,val)" and "self.searchBST(root.right,val)"? If there is no return added for the two lines, would't the program still run recursively until the conditions of root.val == val or root== None is met, and a value is returned? (I know it's not the case in practice, I'm just trying to conceptualize it).
Moreover, could someone kindly show me the general guideline for using return in recursions? Thank you in advance!
If you just write:
self.searchBST(root.left,val)
instead of
return self.searchBST(root.left,val)
it will perform the recursive search but won't return the result back to the block in which it is invoked. When it gets to the value you want (or doesn't find it), that call will do
return root
But the previous call will just discard this value, rather than returning it back up the recursion chain.
A return statement exits the currently running function and returns a return value, which can then be used like any other value in Python: assigned to a variable, passed as the argument to another function, or ... returned as the return value of the calling function.
def some_func():
return 'result'
x = some_func() # after this, x == 'result'
If you call a function without capturing the return value, it just gets lost. So, if you just call some_func(), it will get executed.
some_func() # this works, but 'result' is lost
The same goes for a function that calls another function, even if that other function is itself:
def some_other_func1():
x = some_func()
return x
def some_other_func2():
return some_func() # exact same result as some_other_func1()
def some_recursive_func(n):
if n == 0:
print('Reached the end')
return n
else:
print(f'At {n}, going down')
return some_recursive_func(n-1)
print(some_recursive_func(3)) # prints a bunch of lines, but always prints `0` at the end
Let's take an even simpler example and you can apply the same logic to your method as well,
def fact(n):
#Base case
if n in [0, 1]:
return 1
#Recursion. Eg: when n is 2, this would eventually become 2 * 1 and would be returning 2 to the caller
return n * fact(n-1)
In general a recursive function will have 2 cases, one being the base case and the other being recursive call to self. And remember, this is a function and ideally is supposed to return something to the caller. That is where return statement would be needed. Otherwise you wouldn't be returning right value to the caller.
If there is no return added for the two lines, would't the program still run recursively until the conditions of root.val == val or root== None is met, and a value is returned
Value is returned yes. But it would be returned to previous call (and so on) and hence it would return to one of self.searchBST(root.left,val) or self.searchBST(root.right,val). You would still need to return from this point to the caller of the function. Hence you would need to have return self.searchBST(root.left,val) or return self.searchBST(root.right,val).
There are two solution for a problem:
Problem is :
Enter the root node of a binary tree and an integer to print out the path where the sum of the node values in the binary tree is the input integer. A path is defined as a path from the root node of the tree to the next node until the leaf node passes. (Note: In the list of return values, the array with the largest array length is ahead)
solution one
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def FindPath(self, root, expectNumber):
if not root:
return []
result=[]
path=[root]
path_sum=0
def find(root,path,path_sum):
isleaf= root.left==None and root.right==None # a bool,whether is leaf node
path_sum+=root.val
if isleaf and path_sum==expectNumber:
t=[]
for i in path:
t.append(i.val)
result.append(t) # add a appropriate path's value to result
if path_sum<expectNumber:
if root.left:
find(root.left,path+[root.left],path_sum)#note!!!!!
if root.right:
find(root.right,path+[root.right],path_sum)#note!!!!!
find(root,path,path_sum)
return result
solution 2
class Solution:
def FindPath(self, root, expectNumber):
if not root:
return []
result=[]
path=[]
path_sum=0
def find(root,path,path_sum):
isleaf= root.left==None and root.right==None
path.append(root)#note!!!!!
path_sum+=root.val
if isleaf and path_sum==expectNumber:
t=[]
for i in path:
t.append(i.val)
result.append(t)
if path_sum<expectNumber:
if root.left:
find(root.left,path,path_sum)
if root.right:
find(root.right,path,path_sum)
path.pop()#note!!!!!
find(root,path,path_sum)
return result
I don't know why in solution 1 the path list don't need pop operation but solution 2 need. In other word why solution 1 don't share a path list, but solution 2 does.
Please help me, I cann't find such paper figure me out!
My point is not about class , you can use function to solve this problem too.
What I care is Python variable value assignment in recursion!!!
I find your code has a lot of mistakes that will make it hard to trace:
**** First: any def or function inside any Python class should be lower case with underscores, so we can figure out what is class from a function, so your FindPath() should be >>>>>> find_path()
**** Second: If you wand to declare any arguments to a the global scope of a class, you should do that inside a function as a constructor or initializer, so your code for an E.G should be :
class Solution:
def __init__(self, root, expect_number):
self.root = root
self.expect_number = expect_number
and any time you will call any argument inside the class, you should call it with the (self.arg), e.g self.root
**** Third: this line is not understandable at all :
def find(root,path,path_sum):
isleaf= root.left==None and root.right==None
this is totally wrong you are assigning a None value to preassaigned value to isleaf, and you again give the isleaf variable an (and) word so, as a logical or pythonic logic : how would the isleaf will understand to get the two values (root.left and root.right) which are getting a None values, does not make any sense.
so please give us an idea about what exactly do you want to do here.
**** Fourth: consider to give one space after and before any operator so instead of
"if path_sum
**** Don't afraid to give the variables or arguments a real names to discripe the real needs for it, or at least try to give a comment for it, So e.g : what is t = [] is doing!!!!!!!
So please try to be more specific so you can find good help for your problems, and to make your code more pythonic.
New Edit:
In solution no 2 : every time you call the find() function, you are appending or adding the 'root' value to the path list
def find(root,path,path_sum):
isleaf= root.left==None and root.right==None
path.append(root) # here you added the root to the path
and the code still recursive till this condition is false:
if path_sum<expectNumber:
and when it false, it will start to call the pop() method, which will remove
the last 'root', added to the path list:
path.pop()
and then it calls the next line, which will call the find function again
find(root,path,path_sum)
but this time will call it with empty path value, WHY?
because the first path list object "path=[]" is at the same level scope as
the calling of the last find function "find(root,path,path_sum)"
so the inner path argument and it's values not seen by the outer path scope, they only seen by the find() function it self.
And this scope issues exactly the same to "Solution 1", except you are passing a path list with root value, and when this condition is False
if path_sum<expectNumber:
the code will call the find() function again but with path only having the root value in the first announcement "path=[root]".
And After all I think with respect you are not sharing the whole code for privacy issue, so it's hard to find the answer easily.
You can simplify your recursive method several ways. First, at each iteration, check if the value of the node passed to the method along with the sum of the current path contents is less than or equal to the desired value. Second, should the latter be smaller, call the method on the left and right sides of the tree:
class Solution:
#classmethod
def find_path(cls, head, val:int, current = []):
if sum(current) == val:
yield current
elif head.value+sum(current) < val:
if head.left is not None:
yield from cls.find_path(head.left, val, current+[head.value])
if head.right is not None:
yield from cls.find_path(head.right, val, current+[head.value])
elif head.value+sum(current) == val:
yield current+[head.value]
Tree class for demonstration:
class Tree:
def __init__(self, **kwargs):
self.__dict__ = {i:kwargs.get(i) for i in ['left', 'right', 'value']}
t = Tree(value=10, left=Tree(value=8, left=Tree(value=3), right=Tree(value=5)), right=Tree(value=2, left=Tree(value=2)))
"""
10
/ \
8 2
/ \ /
3 5 2
"""
results = [list(Solution.find_path(t, i)) for i in [12, 14, 23]]
Output:
[[[10, 2]], [[10, 2, 2]], [[10, 8, 5]]]
0
/ \
1 2
/ \ /|\
3 4 5 6 7
I'm trying to return the nodes without children (3,4,5,6,7) from an object using a recursive function.
It works using a global variable and this function:
def find(self, nodes):
if not hasattr(self, 'children'):
nodes.append(self)
else:
for i in self.children:
i.find(nodes)
nodes = []
node.find(nodes) # can be any node (0,1,2,3,4, etc.)
print(nodes)
But I would like to use return in my function. I tried something like this:
def find2(self):
if not hasattr(self, 'children'):
return self
else:
for i in self.children:
return i.find2()
nodes = root.find2()
print(nodes)
But I get only 1 node. I also tried passing an array like on this post: PYTHON Return a list from a recursive function. But I don't get the result I want because tree structure (I guess)...
I'm stuck, can you help me? How to "return the result for each iteration of the recursive function to a variable"? Thank you
This is the input example:
0
/ \
1 2
/ \ /|\
3 4 5 6 7
Think about what you want the (recursive) function to return for each of the nodes:
when called on the root (0), it should return the full result (3, 4, 5, 6, 7)
when called on a leaf node (e.g. 5), it should return that node (5)
for any other node (e.g. 1), it does as if that was a root node of a smaller tree
So, it sometimes returns one result and sometimes many.
The error in your code is here, because the function ends on the first return, it does not return many:
for i in self.children:
return i.find2()
There are two solutions:
make a generator function, or
make a function which returns a list (make it return a list always, even if it has just one element!)
So, option 1:
def find(self):
if not hasattr(self, 'children'):
yield self
else:
for child in self.children:
yield from child.find()
option 2:
def find(self):
if not hasattr(self, 'children'):
return [self]
else:
rtn = []
for child in self.children:
for result in child.find():
rtn.append(result)
return rtn
I prefer the generator. Additionally, I don't particularly like the fact that some of your nodes have a children attribute, while others do not. I would make sure all of them had children, which could be empty or non-empty. Then, the code becomes:
def find_leaves(self):
if self.children:
for child in self.children:
yield from child.find_leaves()
else:
yield self
Note that in your base case, you return one node. That node then get propagated back in the recursion, and eventually returned. I.e. the node you are returned is the first one without children you hit. There are multiple ways to fix this issue (e.g. by returning and concatenating lists), but I think a natural way to do this is to make your function a generator. To do this, simply replace the return by a yield. Then, the return value of the function functions as an iterator, with each iteration yielding the next value that would be "returned" in execution until the function terminates.
You've not provided enough code for me to make a runnable and testable example but here's my guess of what you seek:
def find(self):
if not hasattr(self, 'children'):
return [self]
nodes = []
for child in self.children:
return nodes.extend(child.find())
return nodes
# ...
nodes = root.find()
print(nodes)
I was instructed to find gcd using the Euclid method. I initially wrote the following in Python:
def gcdRecur(a,b):
if b==0:
print('I am here')
return a
else:
gcdRecur(b,a%b)
print(a,b)
print(gcdRecur(51,187))
The result was:
I am here
34 17
51 34
187 51
51 187
None
I had no idea why its output is the way it is, then I realised looking at others code that one is to use the return statement explicitly.
def gcdRecur(a,b):
if b==0:
print('I am here')
return a
else:
return gcdRecur(b,a%b)
print(a,b)
print(gcdRecur(51,187))
I got
I am here
17
So I got what I wanted and learnt that we should use return statement rather then just calling the function.
My question is why is the output of the first code reversed? And why does the following code work even though no return statement is used
def tower(n,fr,to,spare):
if n==1:
print_move(fr,to)
else:
tower(n-1,fr,spare,to)
tower(1,fr,to,spare)
tower(n-1,spare,to,fr)
The above code is what I learnt in MIT course on edX, it is solution to Tower of Hanoi problem.
Here the code works fine. So when I want the implementation in reverse order we call the recursive function directly and in correct order we use a return statement, am I right?
My question is why is the output of the first code reversed?
It is not really reversed in the strict sense, but I think I get what you mean. You perhaps expect that the "parent" call prints before the "child" call.
If we however inspect the code, we see that:
def gcdRecur(a,b):
if b==0:
print('I am here')
return a
else:
gcdRecur(b,a%b) # make child call
print(a,b) # print from the parent call
If you would have swapped the two, it would print in what you probably call the "right way":
def gcdRecur(a,b):
if b==0:
print('I am here')
return a
else:
# swap printing and recursive calls
print(a,b) # print from the parent call
gcdRecur(b,a%b) # make child call
If you use a return statement however, the function is terminated from the moment it reaches a return, so if we print things after the return statement is reached, that printing never happens. In case we want that, we could for instance use a try-finally construct.
More in depth, if we "trace" a program, for example with (this is not valid Python code, it is more to give an insight into how these calls are handled):
gcdRecur(51,187)
if 187 == 0: # fails
else: # we take the else branch
gcdRecur(187,51)
if 51 == 0: # fails
else: # we take the else branch
gcdRecur(51,34)
if 51 == 0: # fails
else: # we take the else branch
gcdRecur(34,17)
if 51 == 0: # fails
else: # we take the else branch
gcdRecur(17,0)
if 0 == 0: # succeeds!
P print('I am here')
return 17
P print(34,17)
P print(51,34)
P print(187,51)
P print(51,187)
I here marked the lines that print with a P at the left. As you can see, the lines with P are in the same order.
Of course you should return the return of your call.
You are doing a method that returns something. In your "else" you return nothing.
So I'm stuck here trying to recursively compare regexes with recursion. The user will create an object with two parameters, each a string of length one. These strings can only be "0", "1" or "2". But I want to recursively check if these strings point to another string as well. Like:
*
/ \
1 2
/ \
2 1
I can't figure out how to recursively point to a new object:
This is what I have so far:
class DotNode(object):
def __init__(self, _cargo, _left=None, _right=None):
self._cargo = _cargo
self._left = _left
self._right = _right
def __eq__(self, _other):
base = ['0','1','2']
if self._left in base and self._right in base:
return self._left == _other._left and self._right == _other._right
else:
while self._left not in base or self._right not in base:
new = self._left
new2 = self._right
new3 = _other._left
new4 = _other._right
return new._left == new3._left and new2._right == new4._right
You seem to already know how to do this: recursion. You want to call the __eq__function recursively here. I would also advice you check if the given cargo is one of the possible values in the constructor - or even better - every time the value is set.
class DotNode(object):
#property
def _cargo(self):
return self._vcargo
#_cargo.setter
def _cargo(self, val):
if val not in ['0', '1', '2']:
raise ValueError("{} is not a possible value for _cargo.".format(val))
self._vcargo = val
def __eq__(self, other):
return isinstance(other, DotNode) and self._cargo == other._cargo and self._left == other._left and self._right == other._right
Breaking it down
Of course you want to keep your constructor here. i just wrote the changed parts down. As you may have noticed you don't even need RegExes here, standard string comparison works just fine.
The _cargo property
I changed _cargo from a simple attribute to a property here. What does that mean? You get getters and setters à la Java that allow better control over the possible values. The actual data is stored in _vcargo of course someone could write to that attribute directly, but that would be downright stupid and you are certainly not responsible if someone uses your code in a way it was not intended. Should you try to set a value different from the possible values, a ValueError will be raised.
The __eq__ function
As you can see this function is actually very simple. Everything it does is compute whether the cargo of the node itself and the other node is equal. Now, if both subtrees are also equal the whole tree is equal. At the deepest level it will compare None with None if both trees are equal, because there will be no more subtrees.