В ваших требованиях не указано, разрешено ли функции изменять порядок списка или нет. Вот возможность:
def remove(items):
items.sort()
running = original = sum(items)
try:
items.index(original) # we just want the exception
return [original]
except ValueError:
pass
if abs(items[0]) > items[-1]:
running -= items.pop(0)
else:
running -= items.pop()
while running != original:
try:
running -= items.pop(items.index(original - running))
except ValueError:
if running > original:
running -= items.pop()
elif running < original:
running -= items.pop(0)
return items
Сортирует список (большие элементы будут в конце, меньшие - в начале), вычисляет сумму и удаляет элемент из списка. Затем он продолжает удалять элементы до тех пор, пока новый итог не будет равен исходному итогу. Альтернативная версия, сохраняющая порядок, может быть записана в виде оболочки:
from copy import copy
def remove_preserve_order(items):
a = remove(copy(items))
return [x for x in items if x in a]
Хотя вам, вероятно, следует переписать это с collections.deque
, если вы действительно хотите сохранить порядок. Если вы можете гарантировать уникальность в своем списке, вы можете получить большой выигрыш, используя вместо этого set
.
Возможно, мы могли бы написать лучшую версию, которая обходит список, чтобы каждый раз находить два числа, наиболее близкие к итоговой сумме, и убирать их ближе к двум, но тогда мы, вероятно, в итоге получили бы производительность O (N ^ 2) , Я полагаю, что производительность этого кода будет O (N * log (N)), поскольку он просто должен отсортировать список (я надеюсь, что сортировка списка Python не O (N ^ 2)), а затем получить сумму.