55. Remove Duplicates from Sorted List II
Problem Statement
Given the head
of a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list. Return the linked list sorted as well.
Example 1:
Input: head = [1,2,3,3,4,4,5] Output: [1,2,5]
Example 2:
Input: head = [1,1,1,2,3] Output: [2,3]
Solution
# Definition for singly-linked list.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
# Create a dummy node to handle cases where the head might be a duplicate
dummy = ListNode(0, head)
prev = dummy
while head:
# If it's a duplicate (current node's value is same as next node's value)
# and next node exists
if head.next and head.val == head.next.val:
# Skip all nodes with the same value
while head.next and head.val == head.next.val:
head = head.next
# Link prev to the node after the duplicates
prev.next = head.next
else:
# Not a duplicate, move prev forward
prev = prev.next
# Move head forward
head = head.next
return dummy.next
Explanation
This problem is a more complex version of "Remove Duplicates from Sorted List". Here, we need to remove all nodes that have duplicate numbers, not just the duplicate occurrences themselves.
Algorithm:
-
Dummy Node: We use a
dummy
node to simplify handling cases where the originalhead
itself might be a duplicate and needs to be removed.prev
pointer is initialized todummy
. -
Iterate with
head
andprev
: We usehead
to traverse the list andprev
to build the new list without duplicates. -
Duplicate Detection and Removal:
- Condition for Duplicate: We check if
head.next
exists and ifhead.val == head.next.val
. This indicates thathead
is part of a sequence of duplicates. - Skip Duplicates: If a duplicate sequence is found, we enter an inner
while
loop. This loop advanceshead
past all nodes that have the same value as the currenthead.val
. - Relink
prev
: After the inner loop,head
will be pointing to the last duplicate node (or the node just before the next distinct value). We then updateprev.next = head.next
. This effectively removes the entire block of duplicate nodes from the list.
- Condition for Duplicate: We check if
-
Non-Duplicate Case: If
head.next
does not exist orhead.val != head.next.val
, it meanshead
is a unique node (or the last node in a sequence of duplicates). In this case, we simply advanceprev
toprev.next
. -
Advance
head
: In both cases (duplicate or not), we advancehead
tohead.next
to continue scanning the list. -
Return Result:
dummy.next
will be the head of the modified list.
Time and Space Complexity:
- Time Complexity: O(n), where n is the number of nodes in the linked list. We iterate through the list once.
- Space Complexity: O(1), as we only use a few extra pointers.