Sometimes, while dealing with graph problems in competitive programming, we have a list of pairs and we need to find if there is a possible cycle in it, and print all the elements in that cycle. Let’s discuss certain way in which this problem can be tackled.
Method 1: Using yield + loop + generator The brute method to perform is to use a generator and keep printing the value if we know that the elements surely form a cycle and this is done by infinite loop and stopping when no more matches are found.
Python3
# Python3 code to demonstrate working of # Join cycle in list # Using yield + loop + generator # helper function to perform this task def cycle(test_list, val, stop = None ): temp = dict (test_list) stop = stop if stop is not None else val while True : yield (val) val = temp.get(val, stop) if val = = stop: break # initializing list test_list = [[ 6 , 7 ], [ 9 , 6 ], [ 7 , 9 ]] # printing original list print ("The original list is : " + str (test_list)) # Join cycle in list # Using yield + loop + generator # printing result print ("The cycle elements are : ") for ele in cycle(test_list, 6 ): print (ele) |
The original list is : [[6, 7], [9, 6], [7, 9]] The cycle elements are : 6 7 9
Time Complexity: O(n)
Space Complexity: O(n)
Method 2: Use a recursive function
- cycle_recursive takes in four arguments: test_list, a list of pairs of values, val, the starting value of the cycle, stop, the optional stopping value of the cycle, and visited, the optional set of visited values.
- If stop is not provided, it is set to val.
- If visited is not provided, an empty set is created.
- The starting value val is added to the visited set and yielded.
next_val is set to None. - For each pair of values in test_list, if the first value of the pair is equal to val, the second value is set to next_val. Similarly, if the second value of the pair is equal to val, the first value is set to next_val.
- If next_val is not None and it has not been visited before, the function is recursively called with next_val as the new starting value, stop and visited as the same as before.
- If next_val is not None but has been visited before, it means that we have found a cycle, so the function is broken out of using the break keyword.
- If next_val is None or is equal to stop, it means we have reached the end of the cycle and the function is returned.
- Finally, an example usage of the function is provided using the same test_list as before. The function is called with val=6 and iterated over to print the cycle elements.
Python3
def cycle_recursive(test_list, val, stop = None , visited = None ): if stop is None : stop = val if visited is None : visited = set () visited.add(val) yield val next_val = None for pair in test_list: if pair[ 0 ] = = val: next_val = pair[ 1 ] elif pair[ 1 ] = = val: next_val = pair[ 0 ] if next_val is not None and next_val not in visited: yield from cycle_recursive(test_list, next_val, stop, visited) break if next_val is None or next_val = = stop: return # example usage test_list = [[ 6 , 7 ], [ 9 , 6 ], [ 7 , 9 ]] print ( "Original list:" , test_list) print ( "Cycle elements:" ) for ele in cycle_recursive(test_list, 6 ): print (ele) |
Original list: [[6, 7], [9, 6], [7, 9]] Cycle elements: 6 7 9
Time complexity: O(n^2)
Auxiliary space: O(1),