Given head of a singly linked list, return the node where a cycle begins. Return null when no cycle exists.
A cycle exists when repeated movement through next pointers reaches an already visited node. The linked list structure must remain unchanged.
Example 1
Input: head = [3, 2, 0, -4], pos = 1
Output: 2
Explanation: Tail connects to index 1, so cycle start value equals 2.
Example 2
Input: head = [1, 2, 3, 4], pos = -1
Output: null
Explanation: Tail points to null, so no cycle exists.
Brute Force Approach
Hash set tracking stores every visited node address during linked list traversal. The first node address encountered twice marks cycle entry because traversal reaches repeated nodes only after entering a cycle.
Concepts include linked list traversal and hash set lookup. The method gives a direct correctness argument and handles empty lists, single-node cycles, and long acyclic prefixes without pointer arithmetic.
Algorithm
Initialize an empty hash set to store visited node addresses, as the address uniquely identifies each node and helps detect when the traversal reaches the same node again.
Initialize
currentashead, since the traversal needs to begin from the first node.Traverse while
currentis notNULL, as every reachable node needs to be checked for repetition.Return
currentwhen it already exists in the hash set, as encountering the same node address again confirms the start of a cycle.Insert
currentinto the hash set and movecurrentto the next node, allowing the traversal to continue while recording every visited node.Return
NULLwhen the traversal reaches the end of the list, since reachingNULLmeans no node was revisited and therefore no cycle exists.
Dry Run
cycle start by hash set
Solution
#include <bits/stdc++.h>using namespace std;class ListNode {public: int data; ListNode* next; ListNode(int value) { data = value; next = nullptr; }};class Solution {public: // Function to find cycle start using hash set. ListNode* findStartingPoint(ListNode* head) { unordered_set<ListNode*> visited; ListNode* current = head; // Traverse nodes until null or repeated address appears. while (current != nullptr) { if (visited.find(current) != visited.end()) { return current; } visited.insert(current); current = current->next; } return nullptr; }};// Function to build linked list and connect tail using position.ListNode* buildList(vector<int>& values, int pos) { if (values.empty()) return nullptr; vector<ListNode*> nodes; for (int value : values) { nodes.push_back(new ListNode(value)); } for (int index = 0; index + 1 < (int)nodes.size(); index++) { nodes[index]->next = nodes[index + 1]; } if (pos >= 0) { nodes.back()->next = nodes[pos]; } return nodes[0];}// Driver code.int main() { vector<int> values = {3, 2, 0, -4}; int pos = 1; ListNode* head = buildList(values, pos); Solution sol; ListNode* answer = sol.findStartingPoint(head); if (answer == nullptr) cout << "null"; else cout << answer->data; return 0;}Complexity Analysis
Time Complexity: O(N), traversal visits each unique node at most once before detecting repetition or reaching null.
Space Complexity: O(N), hash set can store every node address in the linked list.
Optimal Approach
Floyd cycle detection uses two pointers moving at different speeds. Slow pointer moves one step, while fast pointer moves two steps. A cycle forces both pointers to meet inside the cycle; an acyclic list lets fast pointer reach null.
After the first meeting, reset slow pointer to head and keep fast pointer at the meeting node. Move both pointers one step at a time. The meeting node in the second phase is the cycle entry, based on equal distance from head to entry and from meeting point to entry modulo cycle length.
Algorithm
Initialize
slowandfastathead, as the two pointers will move at different speeds to determine whether a cycle exists and where it begins.Traverse while
fastandfast->nextboth exist, since these conditions allowfastto safely move two nodes at a time.Move
slowone node andfasttwo nodes in each iteration, as a cycle will eventually make the faster pointer catch up with the slower pointer.When
slowandfastmeet, resetslowtohead, since the distance from the head to the cycle start relates to the distance from the meeting point to the cycle start.Move both
slowandfastone node at a time until they meet again, as this meeting point is the first node of the cycle.Return the meeting node as the cycle start, since both pointers now converge exactly at the beginning of the cycle.
Return
NULLwhenfastreaches the end of the list, as reachingNULLconfirms that no cycle exists.
Dry Run
starting point
Solution
#include <bits/stdc++.h>using namespace std;class ListNode {public: int data; ListNode* next; ListNode(int value) { data = value; next = nullptr; }};class Solution {public: // Function to find cycle start using Floyd algorithm. ListNode* findStartingPoint(ListNode* head) { ListNode* slow = head; ListNode* fast = head; // Detect cycle by moving pointers at different speeds. while (fast != nullptr && fast->next != nullptr) { slow = slow->next; fast = fast->next->next; if (slow == fast) { slow = head; // Move both pointers equally to reach cycle entry. while (slow != fast) { slow = slow->next; fast = fast->next; } return slow; } } return nullptr; }};// Function to build linked list and connect tail using position.ListNode* buildList(vector<int>& values, int pos) { if (values.empty()) return nullptr; vector<ListNode*> nodes; for (int value : values) { nodes.push_back(new ListNode(value)); } for (int index = 0; index + 1 < (int)nodes.size(); index++) { nodes[index]->next = nodes[index + 1]; } if (pos >= 0) { nodes.back()->next = nodes[pos]; } return nodes[0];}// Driver code.int main() { vector<int> values = {3, 2, 0, -4}; int pos = 1; ListNode* head = buildList(values, pos); Solution sol; ListNode* answer = sol.findStartingPoint(head); if (answer == nullptr) cout << "null"; else cout << answer->data; return 0;}Complexity Analysis
Time Complexity: O(N), pointer movement remains linear across detection and entry-location phases.
Space Complexity: O(1), only slow and fast pointers are used.
Interview follow-up Questions
This problem is a follow-up to Detect a Loop in Linked List, where Floyd's Cycle Detection algorithm is used to determine whether a cycle exists. Once a cycle is detected, the same technique is extended to find its starting node. Q2. Can a single node form a cycle? Yes. If a node's next pointer points back to itself, it forms a cycle, and that node is also the starting node of the cycle.
Be the first to add a comment.