{x}
blog image

Insert into a Sorted Circular Linked List

Solution Explanation

This problem involves inserting a node with a given value (insertVal) into a sorted circular linked list. The challenge lies in maintaining the sorted order and circular nature of the list, even when the list is empty or the insertion point isn't immediately obvious (e.g., when the value is smaller than the smallest or larger than the largest element due to the circular nature).

Approach

The solution efficiently handles all scenarios:

  1. Empty List: If the head is null (empty list), a new node is created, its next pointer points to itself (forming the circular list), and this node is returned as the new head.

  2. Non-Empty List: The algorithm iterates through the list, comparing the current node's value (curr.val) and the previous node's value (prev.val) with the insertVal. The insertion point is found when one of the following conditions is met:

    • prev.val <= insertVal <= curr.val: The insertVal fits between the prev and curr nodes.
    • prev.val > curr.val && (insertVal >= prev.val || insertVal <= curr.val): This condition handles the circularity. If the prev node's value is greater than the curr node's value (meaning we've wrapped around), then insertVal should be inserted either after prev or before curr.
  3. Insertion: Once the correct insertion point (prev and curr) is found, the new node is inserted: prev.next points to the new node, and the new node's next points to curr.

  4. Return Value: The original head is returned. This is important because the head might not be the smallest node in the list, and the insertion might not change which node is the head.

Code Explanation (Python)

The Python code directly implements the approach described above:

class Solution:
    def insert(self, head: 'Optional[Node]', insertVal: int) -> 'Node':
        node = Node(insertVal)  # Create new node
        if head is None:       # Handle empty list
            node.next = node
            return node
        prev, curr = head, head.next  # Initialize pointers
        while curr != head:         # Iterate until we've traversed the whole list
            if prev.val <= insertVal <= curr.val or (prev.val > curr.val and (insertVal >= prev.val or insertVal <= curr.val)):  #check for correct position
                break             # Exit loop once the right place is found
            prev, curr = curr, curr.next  # Move pointers
        prev.next = node       # Insert the node
        node.next = curr
        return head             # Return the original head

The other languages (Java, C++, Go) follow a very similar structure, adapting the syntax to their respective language features. The core logic remains the same.

Time and Space Complexity

  • Time Complexity: O(N), where N is the number of nodes in the list. In the worst case, the algorithm needs to traverse the entire list to find the correct insertion point.

  • Space Complexity: O(1). The algorithm uses a constant amount of extra space, regardless of the list's size. We create one new node, but that's independent of the list size.