1. Brute Force — Hash Set of Seen Values
Intuition
Maintain a hash set of observed values. As we traverse, if curr.next.val is in the set, bypass curr.next; otherwise add it to the set and advance.
Algorithm
- Step 1: If
head == null, returnnull. - Step 2: Create a
HashSetcontaininghead.val. - Step 3:
curr = head. - Step 4: While
curr.next != null: - a. If
set.contains(curr.next.val):curr.next = curr.next.next. - b. Else:
set.add(curr.next.val),curr = curr.next. - Step 5: Return
head.
#include <iostream>#include <unordered_set> using namespace std; struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), next(nullptr) {}}; class Solution {public: ListNode* deleteDuplicates(ListNode* head) { if (!head) return nullptr; unordered_set<int> seen; seen.insert(head->val); ListNode* curr = head; while (curr->next) { if (seen.count(curr->next->val)) { ListNode* toDelete = curr->next; curr->next = curr->next->next; delete toDelete; } else { seen.insert(curr->next->val); curr = curr->next; } } return head; }}; int main() { ListNode* h = new ListNode(1); h->next = new ListNode(1); h->next->next = new ListNode(2); h->next->next->next = new ListNode(3); h->next->next->next->next = new ListNode(3); Solution sol; ListNode* res = sol.deleteDuplicates(h); cout << "Brute Force Deduplicated: "; for (ListNode* c = res; c; c = c->next) cout << c->val << (c->next ? " -> " : ""); cout << endl; return 0;}Time & Space Complexity
- Time complexity:
O(N)— Visits each node once in O(N). Hash set insertions and lookups take O(1). - Space complexity:
O(N)— Allocates a hash set storing up to N distinct values.
Why Brute Force Doesn't Scale:
Hash sets allocate auxiliary buckets and incur hashing overhead.
For N = 100,000 nodes, in-place deduplication runs in <0.5ms.