Я не претендую на лучшее решение, но попробую разъяснить свой код
def filter_num(num):
'''Список для итоговых символов:'''
res = []
'''Список-буфер для временного
хранения дублирующихся символов,
сразу поместили туда 0-й элемент:'''
temp = [num[0]]
'''Начнём перебор с 1-го элемента,
т.к. 0-й уже в буфере:'''
for n in num[1:]:
'''Записываем сразу в переменную значение из буфера,
т.к. оно понадобится больше одного раза,
и нам не придётся каждый раз его
извлекать из списка:'''
old = temp[-1]
'''Если текущее значение не равно предыдущему (old),
то значит пора смотреть, что накопилось в буфере:'''
if old != n:
'''Если в буфере более одного элемента, то у нас не помеха:'''
if len(temp) > 1:
'''Если мы накопили в буфере символы '#', то
добавляем в список res последнее значение
из этого списка, т.е. дублируем поседнюю
цифру из отфильтрованного на текущий
момент номера. На всякий случай перед этим
проверяем, не пуст ли список res
(такое может быть, если на входе из "не помех"
самыми первыми были поданы символы '#'):'''
if res and old == '#':
res.append(res[-1])
'''Если же значение из буфера - цифра, то
добавляем его в итоговый список res:'''
else:
res.append(old)
'''Мы взяли из буфера то что нужно,
или же там был оди символ (помеха), но теперь
мы перезаписываем буфер, помещая туда
новый текущий символ:'''
temp = [n]
'''Если же текущий символ продолжает быть равным old, то добавляем его в буфер temp:'''
else:
temp.append(n)
'''Цикл закончен, но там могут остаться элементы
с последних итераций, когда последние равные элементы
добавлялись в буфер temp, но в res ничего не извлеклось,
т.к. мы не нарвались на символ, отличный от вышеназванных,
и условие if old != n: не выполнилось. Проверяем,
и если это так, добавляем в итоговый
список этот элемент или, если там #, дублируем
последний из res:'''
if len(temp) > 1:
if n == '#':
if res:
res.append(res[-1])
else:
res.append(n)
'''Возвращаем результат, преобразовав содержимое
списка в строку:'''
return ''.join(res)
print(filter_num('32224#6665###9966##555'))