Detecting Cycles and Removing k-th From End Using Two-Pointer Techniques

Given a singly linked list, determine weather it contains a cycle. Return true if a cycle exists; otherwise, return false. The solution must use O(1) auxiliary space.

This problem is classically solved using Floyd’s Cycle Detection Algorrithm — also known as the "tortoise and hare" approach. Two pointers traverse the list at different speeds: one advances by one node per step (slow), the other by two nodes (fast). If a cycle exists, the fast pointer will eventually catch up to the slow pointer inside the loop.

class Solution {
public:
    bool hasCycle(ListNode* head) {
        if (!head || !head->next) return false;

        ListNode* slow = head;
        ListNode* fast = head;

        while (fast && fast->next) {
            slow = slow->next;
            fast = fast->next->next;
            if (slow == fast) return true;
        }

        return false;
    }
};

Next, implement a function to remove the n-th node from the end of the list in a single pass with O(n) time and O(1) space complexity. A sentinel (dummy) node simplifies edge-case handling, especially when deleting the head.

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode dummy(0);
        dummy.next = head;

        ListNode* ahead = &dummy;
        ListNode* behind = &dummy;

        // Advance 'ahead' by n+1 steps to create proper gap
        for (int i = 0; i <= n; ++i) {
            ahead = ahead->next;
        }

        // Move both until 'ahead' reaches null
        while (ahead) {
            ahead = ahead->next;
            behind = behind->next;
        }

        // Remove the target node
        ListNode* toDelete = behind->next;
        behind->next = toDelete->next;
        delete toDelete;

        return dummy.next;
    }
};

Finally, locate the starting node of the cycle, if one exists. Once the two pointers meet in side the loop, reset one pointer to the head while keeping the other at the meeting point. Then advance both one step at a time — their next meeting occurs precisely at the cycle’s entrance.

class Solution {
public:
    ListNode* detectCycle(ListNode* head) {
        if (!head || !head->next) return nullptr;

        ListNode* slow = head;
        ListNode* fast = head;

        // Phase 1: Detect if cycle exists
        do {
            if (!fast || !fast->next) return nullptr;
            slow = slow->next;
            fast = fast->next->next;
        } while (slow != fast);

        // Phase 2: Find cycle entrance
        slow = head;
        while (slow != fast) {
            slow = slow->next;
            fast = fast->next;
        }

        return slow;
    }
};

Tags: linked-list two-pointers floyd-cycle-detection

Posted on Mon, 20 Jul 2026 16:57:01 +0000 by christian_phpbeginner