26. Insert in Sorted Circular Linked List

The problem can be found at the following link: ๐Ÿ”— Question Link

๐Ÿงฉ Problem Description

Given a sorted circular linked list, insert a new node containing a given data value into the list so that it remains a sorted circular linked list.

๐Ÿ“˜ Examples

Example 1:

Input:

head = 1โ†’2โ†’4 (circular), data = 2

Output:

1โ†’2โ†’2โ†’4 (circular)

Explanation:

We insert the new node with 2 after the second node.

image

Example 2:

Input:

head = 1โ†’4โ†’7โ†’9 (circular), data = 5

Output:

1โ†’4โ†’5โ†’7โ†’9 (circular)

Explanation:

We insert the new node with 5 after the node containing 4.

image

๐Ÿ”’ Constraints

  • $2 โ‰ค number of nodes โ‰ค 10^6$

  • $0 โ‰ค node->data โ‰ค 10^6$

  • $0 โ‰ค data โ‰ค 10^6$

โœ… My Approach

Gap Detection

We traverse the circular list looking for the proper "gap" between two consecutive nodes where the new data fits, taking into account the wrapโ€‘around point (largest to smallest).

Algorithm Steps:

  1. Create the new node n with n->data = data.

  2. If head is null, make n->next = n and return n.

  3. Use pointer cur = head.

  4. Loop indefinitely:

    • Let nxt = cur->next.

    • Case 1: Normal gap: if cur->data โ‰ค data โ‰ค nxt->data, insert between cur and nxt.

    • Case 2: Wrapโ€‘around gap: if cur->data > nxt->data (largestโ†’smallest transition) and (data โ‰ฅ cur->data or data โ‰ค nxt->data), insert here.

    • Case 3: Full cycle fallback: if nxt == head, insert here.

    • On insertion: set cur->next = n, n->next = nxt.

    • If data < head->data, update head = n to maintain head as smallest.

    • Break the loop.

  5. Return head.

๐Ÿงฎ Time and Auxiliary Space Complexity

  • Expected Time Complexity: O(n), as in the worst case we traverse all nodes once to find the insertion point.

  • Expected Auxiliary Space Complexity: O(1), since we use only a fixed number of pointers.

๐Ÿง  Code (C++)

class Solution {
  public:
    Node* sortedInsert(Node* head, int data) {
        Node* n = new Node(data);
        if (!head) {
            n->next = n;
            return n;
        }
        Node* cur = head;
        while (true) {
            Node* nxt = cur->next;
            if ((cur->data <= data && data <= nxt->data) ||
                (cur->data > nxt->data && (data >= cur->data || data <= nxt->data)) ||
                nxt == head) {
                cur->next = n;
                n->next = nxt;
                if (data < head->data) head = n;
                break;
            }
            cur = nxt;
        }
        return head;
    }
};
โšก Alternative Approaches

๐Ÿ“Š 2๏ธโƒฃ Linear Traversal with Doโ€‘While Loop

Algorithm Steps:

  1. Create new node n.

  2. If head is null, link n to itself and return.

  3. Set cur = head.

  4. do-while loop until cur returns to head:

    • Let nxt = cur->next.

    • If (cur->data โ‰ค data โ‰ค nxt->data) or at wrapโ€‘point (cur->data > nxt->data and (data โ‰ฅ cur->data or data โ‰ค nxt->data)), do:

      • cur->next = n; n->next = nxt;

      • If data < head->data then head = n.

      • Break.

    • cur = nxt.

  5. Return head.

class Solution {
  public:
    Node* sortedInsert(Node* head, int data) {
        Node* n = new Node(data);
        if (!head) {
            n->next = n;
            return n;
        }
        Node* cur = head;
        do {
            Node* nxt = cur->next;
            if ((cur->data <= data && data <= nxt->data) ||
                (cur->data > nxt->data && (data >= cur->data || data <= nxt->data))) {
                cur->next = n;
                n->next = nxt;
                if (data < head->data) head = n;
                break;
            }
            cur = nxt;
        } while (cur != head);
        return head;
    }
};

โœ… Why This Approach?

  • Uses a clear do-while to guarantee at least one full cycle.

  • Cleaner separation of traversal and insertion logic.

๐Ÿ“ Complexity Analysis:

  • Time: ๐Ÿ”ธ O(n) โ€” one cycle maximum.

  • Space: ๐ŸŸข O(1).

๐Ÿชœ 3๏ธโƒฃ Find Maximum Node Then Insert

Algorithm Steps:

  1. Traverse to find maxNode where maxNode->next == head or data decreases.

  2. Start from maxNode->next (smallest), traverse until correct insert point (cur->data โ‰ค data โ‰ค cur->next->data).

  3. If none found by maxNode, insert after maxNode.

  4. Link new node and update head if needed.

class Solution {
  public:
    Node* sortedInsert(Node* head, int data) {
        Node* n = new Node(data);
        if (!head) { n->next = n; return n; }
        Node* maxNode = head;
        while (maxNode->next != head && maxNode->data <= maxNode->next->data)
            maxNode = maxNode->next;
        Node* cur = maxNode->next;
        while (cur != maxNode && !(cur->data <= data && data <= cur->next->data))
            cur = cur->next;
        if (cur == maxNode && !(cur->data <= data && data <= cur->next->data))
            cur = maxNode;
        n->next = cur->next;
        cur->next = n;
        if (data < head->data) head = n;
        return head;
    }
};

โœ… Why This Approach?

  • Explicitly handles the rotation point.

  • Two-phase traversal: find boundary then insert.

๐Ÿ“ Complexity Analysis:

  • Time: ๐Ÿ”ธ O(n).

  • Space: ๐ŸŸข O(1).

๐Ÿ”ƒ 4๏ธโƒฃ Break, Insert, Reconnect

Algorithm Steps:

  1. Find tail node (where tail->next == head) and break the cycle (tail->next = nullptr).

  2. Perform standard sorted insert on linear list.

  3. Reconnect tail to the new head to restore circularity.

  4. Return the new head.

class Solution {
  public:
    Node* sortedInsert(Node* head, int data) {
        Node* n = new Node(data);
        if (!head) { n->next = n; return n; }
        Node* tail = head;
        while (tail->next != head) tail = tail->next;
        tail->next = nullptr;

        if (data < head->data) {
            n->next = head;
            head = n;
        } else {
            Node* cur = head;
            while (cur->next && cur->next->data < data) cur = cur->next;
            n->next = cur->next;
            cur->next = n;
        }

        tail = head;
        while (tail->next) tail = tail->next;
        tail->next = head;
        return head;
    }
};

โœ… Why This Works:

  • Leverages familiar linear list insert.

  • Easy to debug by isolating circular logic.

๐Ÿ“ Complexity Analysis:

  • Time: ๐Ÿ”ธ O(n).

  • Space: ๐ŸŸข O(1).

๐Ÿ†š Comparison of Approaches

Approach

โฑ๏ธ Time

๐Ÿ—‚๏ธ Space

โœ… Pros

โš ๏ธ Cons

โ–ถ๏ธ Gap Detection (main)

๐ŸŸข O(n)

๐ŸŸข O(1)

Elegant, single pass handles all edge cases

Conditionโ€‘heavy logic

๐Ÿ” Doโ€‘While Traversal

๐Ÿ”ธ O(n)

๐ŸŸข O(1)

Guaranteed cycle, clear syntax

Slightly more verbose

๐Ÿชœ Max Node First

๐Ÿ”ธ O(n)

๐ŸŸข O(1)

Separates boundary detection from insertion

Two traversal phases

๐Ÿ”ƒ Break โ†’ Insert โ†’ Reconnect

๐Ÿ”ธ O(n)

๐ŸŸข O(1)

Simplifies to linear insert + reconnect

Modifies structure temporarily

โœ… Best Choice by Scenario

Scenario

Recommended Approach

๐Ÿ” Want concise, allโ€‘inโ€‘one detection/insert

๐Ÿฅ‡ Gap Detection

๐Ÿ”ง Prefer explicit loop control

๐Ÿฅˆ Doโ€‘While Traversal

๐Ÿงช Need clear boundary then insertion logic

๐Ÿฅ‰ Max Node First

๐Ÿช› Familiar with linear inserts

๐Ÿ”น Break โ†’ Insert โ†’ Reconnect

๐Ÿง‘โ€๐Ÿ’ป Code (Java)

class Solution {
    public Node sortedInsert(Node head, int data) {
        Node n = new Node(data);
        if (head == null) {
            n.next = n;
            return n;
        }
        Node cur = head;
        while (true) {
            if ((cur.data <= data && cur.next.data >= data) ||
                (cur.data > cur.next.data && (data >= cur.data || data <= cur.next.data)) ||
                cur.next == head) {
                n.next = cur.next;
                cur.next = n;
                if (data < head.data) head = n;
                break;
            }
            cur = cur.next;
        }
        return head;
    }
}

๐Ÿ Code (Python)

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


class Solution:
    def sortedInsert(self, head, data):
        n = Node(data)
        if not head:
            n.next = n
            return n
        cur = head
        while True:
            if (cur.data <= data <= cur.next.data or
                cur.data > cur.next.data and (data >= cur.data or data <= cur.next.data) or
                cur.next == head):
                n.next = cur.next
                cur.next = n
                if data < head.data:
                    head = n
                break
            cur = cur.next
        return head

๐Ÿง  Contribution and Support

For discussions, questions, or doubts related to this solution, feel free to connect on LinkedIn: ๐Ÿ“ฌ Any Questions?. Letโ€™s make this learning journey more collaborative!

โญ If you find this helpful, please give this repository a star! โญ


๐Ÿ“Visitor Count

Last updated