Finding cycle in graph using DFS - recursion problem - python

I tried to make an aglorithm that searches for cycles in undirected graph but it seems like return statement doesn't work.
def wrapped_dfs_recursive(G: Dict[int, List[int]], current_vertex: int, parent: int, visited: List[int] = None):
for neighbour in G[current_vertex]:
if neighbour in visited and neighbour != parent:
print("Found cycle")
return True
visited.append(current_vertex)
if current_vertex in G.keys():
for vertex in G[current_vertex]:
if vertex not in visited:
wrapped_dfs_recursive(G, current_vertex=vertex, parent=current_vertex, visited=visited)
else:
return None
return False
When I execute this code for a simple, cyclic graph it returns False, but it also prints the message "Found cycle" two times. So if it executes the print function why doesn't it return True? Did I make something wrong with the stop condition?

Ok, I found the issue. I missed the word 'return' when I was calling wrapped_dfs_recursive(), so it wasn't changing anything and finally returned False.

Related

Trouble returning bool from recursive function

I'm working on a homework problem in which we have to write an algorithm that can determine if a graph is bipartite or not. My python solution works, but right now it throws an exception if the graph is not bipartite, instead I would like it to return a bool. How could I modify this code?
def is_bipartite(v, visited, colors, counter):
print(v)
# Set this vertex to visited
visited[v] = True
colors[v] = counter % 2
# Explore links
for u in v.links:
# If linked up node u has already been visited, check its color to see if it breaks
# the bipartite of the graph
if u in visited:
if colors[v] == colors[u]:
raise Exception("Not Bipartite")
# If the link has not be visited then visit it
if u not in visited:
visited[u] = False
is_bipartite(u, visited, colors, counter + 1)
If I understand your code correctly, you want to return False if you get matching colors anywhere along your recursive search. You want to return True if you get to the end of the search without finding anything.
That is not too hard to do. Just change the raise statement to return False and check the result of the recursive calls, and return False if any of them return a False result. Then just put return True at the end of the function and you're done:
def is_bipartite(v, visited, colors, counter):
visited[v] = True
colors[v] = counter % 2
for u in v.links:
if u in visited:
if colors[v] == colors[u]:
return False # return instead of raise in this base case
if u not in visited:
visited[u] = False
if not is_bipartite(u, visited, colors, counter + 1): # check the recursion
return False # pass on any False
return True # return True only if you got to the end without returning False above

Python: why contents of list are different inside and outside function?

I have a function doing binary tree traversal, and I have a global list "stack" to store temporary values.
stack = []
def search(root, v):
global stack
stack.append(root.info)
if root.info == v:
print(stack) #<------- THE FIRST PRINT IS HERE
return
if root.left is not None:
search(root.left, v)
if root.right is not None:
search(root.right, v)
stack.pop()
pass
def lca(root, v1, v2):
search(root,v1)
print(stack) #<------- THE SECOND PRINT IS HERE
Your Output (stdout)
[4, 2, 1]
[4]
input: v1=1, v2=7
When I print the value of the list from inside and outside the function, I found that the results are different -- when printed inside, the result is [4,2,1], and outside is [4]. I have tried different ways, such as creating the list outside the function, and then pass it to the function, the result is always the same. Can anyone know why this happened?
You seem to believe that after you hit the explicit return in your search function, your recursive search stops. But it doesn't. The search calls higher up the call stack will still go on triggering more searches, popping things off stack, altering its contents.
Perhaps you want something like this: use a return value to signal from search when it has successfully found the thing it was looking for, and don't search any more after that happens.
def search(root, v):
global stack
stack.append(root.info)
if root.info == v:
print(stack)
return True
if root.left is not None and search(root.left, v):
return True
if root.right is not None and search(root.right, v):
return True
stack.pop()
return False
This will prevent the stack being altered after the point where the value is found.

algorythm to find "next neighbor matching" in a multi branch tree

I have a data structure that essentially is a tree with multiple branching.
The program is implemented in python (3.5, currently, if it matters).
Problem:
Starting from an arbitrary node find a "matching" node which is at the shortest possible distance.
Definition of "distance" is having the least possible number of "backtracking" (a backtrack happens when reaching back to parent from the starting node).
This means children of start node are preferred, then come children of parent of starting node, third choice are children of parent of parent of starting node, etc.
Naive implementation leads to infinite recursion:
def find(self, name, skip=None):
if self.name == name:
return self
for c in self.child:
if c != skip:
s = c.find(name, skip)
if s is not None:
return s
if name != 'Start':
if self.parnt is not None:
return self.parnt.find(name, self)
return None
I have not found an algorithm not needing branch tagging, which is cumbersome.
Current implementation has also the problem it implements a depth-first search, while a breadth-first would be preferred.
Can someone suggest an efficient algorithm?
I found a way of doing this with the following code:
def find(self, name, tovisit=None, visited=None):
if tovisit is None:
tovisit = []
if visited is None:
visited = []
tovisit.append(self)
while tovisit:
s = tovisit.pop()
visited.append(s)
if s.name == name:
return s
for c in s.child:
if c not in visited:
tovisit.append(c)
if name != 'Start':
if s.parnt is not None and s.parnt not in visited:
tovisit.append(s.parnt)
return None
This iterative solution relies on two lists to handle breadth-first and avoid re-visiting nodes.
I will not accept my own answer for a while in hope a better solution may be proposed.

Palindrome Linked List in Python with O(1) Extra Space

This is the #234 Leetcode problem:
Given a singly linked list, determine if it is a palindrome.
Follow up: Could you do it in O(n) time and O(1) space?
This problem is easy to solve with O(n) space. However, I cannot figure out the O(1) solution. The only way I think of is to use recursion:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
current = None
def isPalindrome(self, head):
"""
:type head: ListNode
:rtype: bool
"""
if not head or not head.next:
return True
self.current = head
return self.compare(head)
def compare(self, head):
if not head: return True
if not self.compare(head.next): return False
if head.val != self.current.val:
return False
else:
self.current = self.current.next
return True
This works with small samples but gives
maximum recursion depth exceeded
Anyone can provide a solution using only O(1) space? Thank you.
If you are allowed to modify the list in place, you can do the following:
Iterate over the list to count how many elements there are.
Iterate a second time, and starting from the middle of the list, reverse the pointers in the list nodes so that they point to the previous node rather than the next. Remember the last node.
Now you have a pointer to the first node and the last node, and can iterate towards the middle from either end, until you either find a difference (no palindrome) or reach the middle (palindrome).
Reverse the pointers in the second half to bring them back to their original state.
This will only require constant additional space, and has linear execution time.
I commented key points on the solution:
class Solution:
def with_array(self,head:ListNode)->bool:
# this makes S:O(N)
nums=[]
while head:
nums.append(head.val)
head=head.next
l,r=0,len(nums)-1
while l<=r:
if nums[l]!=nums[r]:
return False
l+=1
r-=1
return True
def optimum(self,head:ListNode)->bool:
fast_pointer=head
slow_pointer=head
# I wanna reach the end of the linked list. I stop when fast_pointer.next=None
while fast_pointer and fast_pointer.next:
# we are forwarding fast_pointer twice
fast_pointer=fast_pointer.next.next
# while slow reach middle, fast will reach to the end
slow_pointer=slow_pointer.next
# at the end of this while loop, slow_pointer will be in middle, fast_pointer will be at the end
# reverse the second half of the list, from slow_pointer till the fast_pointer
# at the end of the reverse, prev will point to the last node
prev=None
while slow_pointer:
temp=slow_pointer.next
slow_pointer.next=prev
# eventually prev will point to the last node
prev=slow_pointer
slow_pointer=temp
# check if it is a palindrome
# remember, after reversing, prev=tail
left,right=head,prev
while right:
if left.val!=right.val:
return False
left=left.next
right=right.next
return True

Finding a node in a tree

I am having trouble finding a node in a tree with arbitrary branching factor. Each Node carries data and has zero or greater children. The search method is inside the Node class and
checks to see if that Node carries data and then checks all of that Nodes children. I keep ending up with infinite loops in my recursive method, any help?
def find(self, x):
_level = [self]
_nextlevel = []
if _level == []:
return None
else:
for node in _level:
if node.data is x:
return node
_nextlevel += node.children
_level = _nextlevel
return self.find(x) + _level
The find method is in the Node class and checks if data x is in the node the method is called from, then checks all of that nodes children. I keep getting an infinite loop, really stuck at this point any insight would be appreciated.
There are a few issues with this code. First, note that on line 2 you have _level = [self]. that means the if _level == [] on line 5 will always be false.
The 2nd issue is that your for loop goes over everything in _level, but, as noted above, that will always be [self] due to line 2.
The 3rd issue is the return statement. You have return self.find(x) + _level. That gets evaluated in 2 parts. First, call self.find(x), then concatenate what that returns with the contents of _level. But, when you call self.find(x) that will call the same method with the same arguments and that, in turn, will then hit the same return self.find(x) + _level line, which will call the same method again, and on and on forever.
A simple pattern for recursive searches is to use a generator. That makes it easy to pass up the answers to calling code without managing the state of the recursion yourself.
class Example(object):
def __init__(self, datum, *children):
self.Children = list(children) # < assumed to be of the same or duck-similar class
self.Datum = datum
def GetChildren(self):
for item in self.Children:
for subitem in item.GetChildren():
yield subitem
yield item
def FindInChildren(self, query): # where query is an expression that is true for desired data
for item in self.GetChildren():
if query(item):
yield item

Categories