Circular Linked List

 A circular linked list is a variation of the linked list where the last node's next reference points back to the first node, forming a loop. This allows for circular traversal and is useful in certain scenarios.

In Python, we can implement a circular linked list by creating a Node class and a CircularLinkedList class that manages the nodes.


class Node:
    def __init__(self, value):
        self.value = value
        self.next = None

class CircularLinkedList:
    def __init__(self):
        self.head = None

    def insert(self, value):
        # Create a new node with the given value
        new_node = Node(value)
        
        # If the linked list is empty, set the new node as the head
        if self.head is None:
            self.head = new_node
            self.head.next = self.head
        else:
            # Traverse to the end of the list and append the new node
            curr = self.head
            while curr.next != self.head:
                curr = curr.next
            curr.next = new_node
            new_node.next = self.head

    def delete(self, value):
        if self.head is None:
            return
        
        # If the head node has the value, update the head to the next node
        if self.head.value == value:
            curr = self.head
            while curr.next != self.head:
                curr = curr.next
            curr.next = self.head.next
            self.head = self.head.next
            return

        # Traverse the linked list to find the node with the given value
        curr = self.head
        prev = None
        while curr.next != self.head:
            if curr.value == value:
                # Remove the node by updating the previous node's next reference
                prev.next = curr.next
                return
            prev = curr
            curr = curr.next
        
        # Check if the last node has the value
        if curr.value == value:
            prev.next = self.head

    def search(self, value):
        # Traverse the circular linked list to find the node with the given value
        curr = self.head
        while True:
            if curr.value == value:
                return True
            curr = curr.next
            if curr == self.head:
                break
        return False


Now let's solve a question from LeetCode using the Circular Linked List. Consider the problem "Linked List Cycle" (LeetCode #141), where we need to determine if a linked list has a cycle. 


def has_cycle(head):
    slow = head
    fast = head

    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next

        if slow == fast:
            return True

    return False


In this example, we use the "Floyd's Tortoise and Hare" algorithm to detect a cycle in the linked list. We initialize two pointers, slow and fast, both starting from the head. The slow pointer moves one step at a time, while the fast pointer moves two steps at a time. If there is a cycle, the fast pointer will eventually catch up to the slow pointer. If the fast pointer reaches the end of the list (i.e., it becomes None), then there is no cycle. We return True if a cycle is detected and False otherwise.

The time complexity of the has_cycle function is O(N), where N is the number of nodes in the linked list. In the worst case, the fast pointer will travel the entire linked list before determining the absence of a cycle.

Here's another example of solving a LeetCode problem using the Circular Linked List concept. Let's consider the problem "Find the Duplicate Number" (LeetCode #287).

Problem statement: Given an array of integers nums containing n + 1 integers where each integer is in the range [1, n] inclusive. There is only one duplicate number in nums, return this duplicate number.

Example: Input: nums = [1,3,4,2,2] Output: 2

To solve this problem, we can utilize the concept of the Floyd's Tortoise and Hare algorithm to find the duplicate number.


def find_duplicate(nums):
    slow = nums[0]
    fast = nums[0]

    # Move slow and fast pointers
    while True:
        slow = nums[slow]
        fast = nums[nums[fast]]

        if slow == fast:
            break

    # Find the entrance of the cycle
    slow = nums[0]
    while slow != fast:
        slow = nums[slow]
        fast = nums[fast]

    return slow


In this example, we initialize two pointers, slow and fast, to the first element of the nums array. We update the slow pointer by accessing the value at the corresponding index in nums, and the fast pointer by accessing the value at the index of the value at the corresponding index in nums. We repeat this process until the pointers meet at the same value. This indicates the presence of a cycle.

Once we detect the cycle, we reset the slow pointer to the first element of the nums array and move both the slow and fast pointers one step at a time. The point at which they meet again is the entrance of the cycle. In the context of the problem, this entrance represents the duplicate number.

The time complexity of the find_duplicate function is O(n), where n is the length of the nums array. The space complexity is O(1), as we are using constant extra space for the pointers.

 

 

 

Next Post Previous Post