🧠
Brute Force (Nested Loops to Identify and Remove Duplicates)
💡 Starting with brute force helps understand the problem deeply by explicitly checking each node and removing duplicates step-by-step, even if inefficient.
Intuition
Traverse the list and for each node, check if it has duplicates by scanning ahead. If duplicates are found, remove all nodes with that value.
Algorithm
- Initialize a dummy node pointing to head to handle edge cases.
- Use two pointers: prev (initially dummy) and current (initially head).
- For each current node, check if next nodes have the same value.
- If duplicates found, skip all nodes with that value by adjusting prev.next.
- Otherwise, move prev to current.
- Move current forward until end of list.
💡 The main challenge is detecting and skipping entire runs of duplicates, not just one node, which requires nested scanning.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def deleteDuplicates(head):
dummy = ListNode(0, head)
prev = dummy
current = head
while current:
# Check if current is start of duplicates
if current.next and current.val == current.next.val:
# Skip all nodes with current.val
val_to_remove = current.val
while current and current.val == val_to_remove:
current = current.next
prev.next = current
else:
prev = current
current = current.next
return dummy.next
# Driver code to test
if __name__ == '__main__':
# Helper to create list
def create_list(arr):
dummy = ListNode(0)
cur = dummy
for v in arr:
cur.next = ListNode(v)
cur = cur.next
return dummy.next
# Helper to print list
def print_list(node):
vals = []
while node:
vals.append(str(node.val))
node = node.next
print('[' + ','.join(vals) + ']')
head = create_list([1,2,3,3,4,4,5])
res = deleteDuplicates(head)
print_list(res) # Expected: [1,2,5]
Line Notes
dummy = ListNode(0, head)Create dummy to simplify edge cases like duplicates at head
prev = dummyPrev tracks last node before current run, needed to reconnect list
while current:Traverse entire list until no nodes left
if current.next and current.val == current.next.val:Detect start of duplicates by comparing current and next values
while current and current.val == val_to_remove:Skip all nodes with duplicate value
prev.next = currentLink prev to first non-duplicate node after duplicates
else:If no duplicates, move prev forward
return dummy.nextReturn head of modified list, skipping dummy
class ListNode {
int val;
ListNode next;
ListNode(int val) { this.val = val; }
}
public class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode prev = dummy;
ListNode current = head;
while (current != null) {
if (current.next != null && current.val == current.next.val) {
int valToRemove = current.val;
while (current != null && current.val == valToRemove) {
current = current.next;
}
prev.next = current;
} else {
prev = current;
current = current.next;
}
}
return dummy.next;
}
// Driver code
public static void main(String[] args) {
Solution sol = new Solution();
ListNode head = createList(new int[]{1,2,3,3,4,4,5});
ListNode res = sol.deleteDuplicates(head);
printList(res); // Expected: [1,2,5]
}
static ListNode createList(int[] arr) {
ListNode dummy = new ListNode(0);
ListNode cur = dummy;
for (int v : arr) {
cur.next = new ListNode(v);
cur = cur.next;
}
return dummy.next;
}
static void printList(ListNode node) {
StringBuilder sb = new StringBuilder();
sb.append("[");
while (node != null) {
sb.append(node.val);
if (node.next != null) sb.append(",");
node = node.next;
}
sb.append("]");
System.out.println(sb.toString());
}
}
Line Notes
ListNode dummy = new ListNode(0);Dummy node to handle edge cases uniformly
ListNode prev = dummy;Prev pointer to reconnect list after removing duplicates
while (current != null)Traverse all nodes in the list
if (current.next != null && current.val == current.next.val)Detect duplicate sequence start
while (current != null && current.val == valToRemove)Skip all nodes with duplicate value
prev.next = current;Link prev to node after duplicates
else { prev = current; current = current.next; }Move pointers forward if no duplicates
return dummy.next;Return new head skipping dummy
#include <iostream>
using namespace std;
struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(nullptr) {}
};
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
ListNode dummy(0);
dummy.next = head;
ListNode* prev = &dummy;
ListNode* current = head;
while (current) {
if (current->next && current->val == current->next->val) {
int valToRemove = current->val;
while (current && current->val == valToRemove) {
current = current->next;
}
prev->next = current;
} else {
prev = current;
current = current->next;
}
}
return dummy.next;
}
};
// Helper functions
ListNode* createList(int arr[], int n) {
ListNode dummy(0);
ListNode* cur = &dummy;
for (int i = 0; i < n; i++) {
cur->next = new ListNode(arr[i]);
cur = cur->next;
}
return dummy.next;
}
void printList(ListNode* head) {
cout << "[";
while (head) {
cout << head->val;
if (head->next) cout << ",";
head = head->next;
}
cout << "]" << endl;
}
int main() {
int arr[] = {1,2,3,3,4,4,5};
ListNode* head = createList(arr, 7);
Solution sol;
ListNode* res = sol.deleteDuplicates(head);
printList(res); // Expected: [1,2,5]
return 0;
}
Line Notes
ListNode dummy(0);Dummy node simplifies edge case handling
ListNode* prev = &dummy;Prev pointer to reconnect after duplicates
while (current) {Traverse entire list
if (current->next && current->val == current->next->val) {Detect duplicate sequence start
while (current && current->val == valToRemove) {Skip all duplicates
prev->next = current;Link prev to node after duplicates
else { prev = current; current = current->next; }Move pointers forward if no duplicates
return dummy.next;Return new head skipping dummy
function ListNode(val, next = null) {
this.val = val;
this.next = next;
}
function deleteDuplicates(head) {
let dummy = new ListNode(0, head);
let prev = dummy;
let current = head;
while (current) {
if (current.next && current.val === current.next.val) {
let valToRemove = current.val;
while (current && current.val === valToRemove) {
current = current.next;
}
prev.next = current;
} else {
prev = current;
current = current.next;
}
}
return dummy.next;
}
// Helper to create list
function createList(arr) {
let dummy = new ListNode(0);
let cur = dummy;
for (let v of arr) {
cur.next = new ListNode(v);
cur = cur.next;
}
return dummy.next;
}
// Helper to print list
function printList(head) {
let vals = [];
while (head) {
vals.push(head.val);
head = head.next;
}
console.log('[' + vals.join(',') + ']');
}
// Test
let head = createList([1,2,3,3,4,4,5]);
let res = deleteDuplicates(head);
printList(res); // Expected: [1,2,5]
Line Notes
let dummy = new ListNode(0, head);Dummy node to handle edge cases uniformly
let prev = dummy;Prev pointer to reconnect list after duplicates
while (current) {Traverse all nodes
if (current.next && current.val === current.next.val) {Detect start of duplicates
while (current && current.val === valToRemove) {Skip all duplicates
prev.next = current;Link prev to node after duplicates
else { prev = current; current = current.next; }Move pointers forward if no duplicates
return dummy.next;Return new head skipping dummy
Traverse the list once, skipping duplicates in a single pass without nested loops.
💡 For n=20, this means about 20 operations, which is efficient for large inputs.
Interview Verdict: Accepted / Optimal iterative solution
This approach is preferred in interviews due to its clarity and efficiency.