1. Brute Force — Hash Set Visited Pointers
Intuition
Iterate through the list and record visited node references in a hash set. If the current pointer is already in the set, we have looped back, indicating a cycle.
Algorithm
- Step 1: Create an empty
HashSetofListNode*. - Step 2: Initialize
curr = head. - Step 3: While
curr != null: - a. If
set.contains(curr), returntrue. - b. Add
currtoset. - c. Advance
curr = curr.next. - Step 4: If
curr == null, returnfalse.
#include <iostream>#include <unordered_set> using namespace std; struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(nullptr) {}}; class Solution {public: bool hasCycle(ListNode *head) { unordered_set<ListNode*> visited; ListNode* curr = head; while (curr) { if (visited.count(curr)) { return true; } visited.insert(curr); curr = curr->next; } return false; }}; int main() { ListNode* n1 = new ListNode(3); ListNode* n2 = new ListNode(2); ListNode* n3 = new ListNode(0); ListNode* n4 = new ListNode(-4); n1->next = n2; n2->next = n3; n3->next = n4; n4->next = n2; // cycle Solution sol; cout << "Brute Force hasCycle: " << (sol.hasCycle(n1) ? "true" : "false") << endl; return 0;}Time & Space Complexity
- Time complexity:
O(N)— Visits each node at most once before finding a duplicate or hitting null. Hash set insert and lookup take O(1) average time. - Space complexity:
O(N)— Stores up to N node references in the hash set.
Why Brute Force Doesn't Scale:
Hash set allocations cause cache misses and trigger GC pressure on large graphs.
For N = 10,000 nodes, Floyd's pointer loop runs in ~0.05ms with 0 heap bytes allocated.