Проанализируйте следующий фрагмент Python-кода и предложите более эффективный алгоритм и структуру данных, объяснив временную и пространственную сложность исходного и улучшенного решений:
def unique_pairs(arr):
res = []
for i in range(len(arr)):
for j in range(i+1, len(arr)):
if arr[i] + arr[j] == 0:
res.append((arr[i], arr[j]))
return res

30 Окт в 09:26
5 +1
0
Ответы
1
Анализ исходного кода
- Вложенные циклы пробегают все пары индексов: время работы O(n2)O(n^2)O(n2), где n=n = n= len(arr).
- Дополнительная память помимо результата — константна O(1)O(1)O(1); итоговый список пар может иметь в худшем случае Θ(n2)\Theta(n^2)Θ(n2) элементов, т.е. итоговая память O(n2)O(n^2)O(n2).
Задача уточнения: надо ли возвращать все индексные пары (как в оригинале) или только уникальные по значению пары. Предложу оба эффективных варианта.
1) Если нужен только один экземпляр каждой пары значений (каждая комбинация x,−xx,-xx,x — один раз)
Алгоритм: проход по массиву с множеством "seen" и множеством результатов (чтобы не дублировать).
Время: O(n)O(n)O(n). Память: O(n+p)O(n + p)O(n+p), где ppp — число уникальных пар (обычно p≤np \le npn).
Пример (псевдо-/Python):
def unique_value_pairs(arr):
seen = set()
res = set()
for x in arr:
if -x in seen:
a, b = (x, -x) if x <= -x else (-x, x)
res.add((a, b))
seen.add(x)
return list(res)
Особенность: нули добавятся как одна пара (0,0)(0,0)(0,0) только если есть хотя бы два нуля.
2) Если нужно точно те же все индексные пары (включая дубликаты по индексам)
Алгоритм: хеш-таблица, хранящая ранее встретившиеся значения (или их индексы / счётчики). При обработке текущего элемента сразу генерируем пары с уже встреченными дополнениями — каждый индексный набор генерируется ровно один раз.
Время: O(n+k)O(n + k)O(n+k), где kkk — число возвращаемых пар (включая k=Θ(n2)k= \Theta(n^2)k=Θ(n2) в худшем случае). Память: O(n+k)O(n + k)O(n+k).
Пример:
from collections import defaultdict
def all_index_pairs(arr):
positions = defaultdict(list) # value -> list of indices (или просто counts, если не нужны индексы)
res = []
for j, x in enumerate(arr):
comp = -x
for i in positions[comp]: # генерация всех пар (i,j) с суммой 0
res.append((arr[i], arr[j]))
positions[x].append(j)
return res
Особенность: для нулей будет сгенерировано (c2)\binom{c}{2}(2c ) пар, где ccc — количество нулей.
Выводы по сложностям
- Исходный: время O(n2)O(n^2)O(n2), доп. память O(1)O(1)O(1) (без результата), память с результатом — до O(n2)O(n^2)O(n2).
- Улучшенный (уникальные значения): время O(n)O(n)O(n), память O(n)O(n)O(n).
- Улучшенный (все индексные пары): время O(n+k)O(n + k)O(n+k), память O(n+k)O(n + k)O(n+k), где kkk — число возвращаемых пар.
Выберите вариант в зависимости от требуемой семантики результата (уникальные по значению или все индексные пары).
30 Окт в 09:43
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир