Given the head
of an unsorted linked list, write a function to remove all the duplicate nodes from the list.
Example 1:
Input: head = [1,2,3,2,1]
Output: [1,2,3]
Explanation: The linked list should contain only distinct values.
Example 2:
Input: head = [1,3,1,4,5,5,2,3]
Output: [1,3,4,5,2]
Explanation: The linked list should contain only distinct values.
Constraints:
[0, 104]
.-105 <= Node.val <= 105
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force method for removing duplicates in a linked list is simple but inefficient. We go through each item in the list and, for each item, we check all the other items to see if they are the same.
Here's how the algorithm would work step-by-step:
class Node:
def __init__(self, data):
self.data = data
self.next = None
def remove_duplicates_brute_force(head):
current_node = head
# Iterate through each node in the list.
while current_node:
runner = current_node
# Compare the current node with all subsequent nodes.
while runner.next:
if runner.next.data == current_node.data:
# Remove duplicate node if found
runner.next = runner.next.next
else:
runner = runner.next
current_node = current_node.next
return head
To remove duplicate items from a linked list efficiently, we'll keep track of items we've seen before. This allows us to quickly identify and skip over duplicates as we go through the list. We use extra storage to make the removal process faster.
Here's how the algorithm would work step-by-step:
class Node:
def __init__(self, data):
self.data = data
self.next = None
def remove_duplicates_from_unsorted_linked_list(head):
if not head:
return head
seen_values = set()
current_node = head
previous_node = None
while current_node:
# Check if the current node's data is a duplicate
if current_node.data in seen_values:
# Remove duplicate by skipping the current node
previous_node.next = current_node.next
current_node = current_node.next
else:
# Add current node's data to seen values
seen_values.add(current_node.data)
previous_node = current_node
current_node = current_node.next
return head
Case | How to Handle |
---|---|
Null or empty linked list | Return null immediately as there are no nodes to process. |
Linked list with only one node | Return the head directly as there are no other nodes to compare it against. |
Linked list with all nodes having the same value | The solution should remove all but the first node, leaving a single node linked list. |
Linked list with a large number of nodes | The solution's time complexity (O(n) with a hash set) should be efficient enough to handle a reasonable number of nodes; consider memory constraints for extremely large lists. |
Linked list with many duplicate values clustered together | The hash set approach efficiently removes consecutive duplicates without unnecessary traversals. |
Linked list containing negative, zero, and positive values | The solution's hashing mechanism should handle all integer values without issues. |
Linked list where the first node is a duplicate and needs to be removed. | Correctly handle removing the head node if it's a duplicate, updating the head pointer. |
Memory Constraints with Extremely Long List | If the list is too large to fit the set in memory, consider using an external sort based approach which will have much higher time complexity (n log n) but will be memory efficient. |