Дан фрагмент Python: def unique_order(arr): res=[]\n for x in arr:\n if x not in res:\n res.append(x)\n return res\nПроанализируйте асимптотику этого кода, предложите более эффективную реализацию, обсудите компромиссы между скоростью и сохранением порядка

17 Мар в 08:37
16 +1
0
Ответы
1
Анализ исходного кода
- Операция `if x not in res` для списка — поиск за линейное время по текущей длине `res`. Для входа длины nnn суммарная сложность примерно ∑i=1ni=O(n2)\sum_{i=1}^{n} i = O(n^2)i=1n i=O(n2).
- Память: результирующий список может содержать до nnn элементов, значит пространство O(n)O(n)O(n).
Итого: время O(n2)O(n^2)O(n2), память O(n)O(n)O(n).
Более эффективные реализации
1) Для хешируемых элементов (рекомендуемая, среднее время линейное):
```
def unique_order(arr):
seen = set()
res = []
for x in arr:
if x not in seen:
seen.add(x)
res.append(x)
return res
```
- Время: в среднем O(n)O(n)O(n) (операции множества — амортизированно O(1)O(1)O(1)), худший теоретический случай для плохо распределённых хешей — O(n2)O(n^2)O(n2) (редко на практике).
- Память: O(n)O(n)O(n).
- Сохраняет порядок первых вхождений.
2) Короткая реализация в Python 3.7+ для хешируемых элементов:
```
def unique_order(arr):
return list(dict.fromkeys(arr))
```
- Эквивалентно O(n)O(n)O(n) в среднем, сохраняет порядок.
3) Если элементы не хешируемы (например, списки):
- Преобразовать элементы в хешируемую форму (если корректно): `tuple(x)` для списков, или использовать ключ-функцию:
```
def unique_order(arr, key=lambda x: x):
seen = set()
res = []
for x in arr:
k = key(x)
if k not in seen:
seen.add(k)
res.append(x)
return res
```
- Если преобразование/ключ невозможны, придётся использовать список `seen` и вернуться к O(n2)O(n^2)O(n2).
Компромиссы между скоростью и сохранением порядка
- Самый быстрый способ без сохранения порядка — `set(arr)` за O(n)O(n)O(n) средне, но порядок теряется.
- Методы с `set`/`dict` дают лучшую скорость и сохраняют порядок первых вхождений при сохранении дополнительной памяти O(n)O(n)O(n).
- Если память критична и элементы не хешируемы, можно пытаться делать удаление «на месте», но это обычно приводит к O(n2)O(n^2)O(n2) времени.
- Выбор зависит от требований: если нужен порядок + скорость → `seen=set()` + список (или `dict.fromkeys`), если порядок не важен → `set(arr)`, если элементы не хешируемы → либо преобразование ключа, либо остаёмся при O(n2)O(n^2)O(n2).
17 Мар в 08:41
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир