Воспринимайте tail и head не в глобальном контексте, а локально. Это всего лишьпеременные с таким именем. Вкаждом конкретном случае и на каждой итерации они могут означать разные места связного списка.
Представьте, что вас много, вы на соревнованиях, у каждого на груди номер и вас выстроили по неубыванию номера в колонну, попросив положить руку на плечо впереди стоящего.
Некоторые номера повторяются и Солюшн Иванович (тренер) идёт вдоль вашей цепочки и делает в точности то, что написано в алгоритме.
При этом там где он идёт, он расцепляет вашу цепочку формируя новую уже без дубликатов.
При этом tail - это хвост новой цепочки, он на каждом шагу новый. Каждому новому хвосту следующим эементом (новым хвостом ставится очередной, но если у него отличный номер. Так тренер выпнет всех с неуникальными номерами из цепочки.
Что конкрено не понятно?
Вот поэкспериментируйте сами:
class ListNode:
def __init__(self, val, next=None):
self.val = val
self.next = next
def __str__(self):
tail = self.next and f', {self.next}' or ''
return f'{self.val!r}{tail}'
def __next__(self):
if self.next:
return self.next
raise StopIteration
def __iter__(self):
item = self
while item:
yield item.val
item = item.next
def copy(self):
return ListNode(self.val, self.next and self.next.copy())
__repr__ = __str__
ln=ListNode; l=ln(1, ln(1, ln(2, ln(3, ln(3)))))