В приведённом фрагменте Python-функции для нахождения максимальной подпоследовательности с суммой > 0 выявите ошибки/неэффективности, оцените временную сложность и предложите более оптимальный алгоритм с объяснением (код): def max_positive_subseq(arr): best = [] for i in range(len(arr)): for j in range(i, len(arr)): s = sum(arr[i:j+1]) if s > 0 and s > sum(best): best = arr[i:j+1] return best
Повторный подсчёт суммы среза в цикле: sum(arr[i:j+1]) — это (O(n)) внутри двойного цикла, даёт общую сложность (O(n^3)).Частые вызовы sum(best) в сравнении (ещё дополнительная трата времени).Присваивание best = arr[i:j+1] копирует срез (ещё затраты на память/время).Поведение при пустом массиве и при всех неположительных элементах формально корректно (возвращает []), но это не документировано.
Временная сложность:
Оригинальный код: (O(n^3)).Простое улучшение с префиксными суммами: (O(n^2)) (предвычислить (P), где (S(i,j)=P_{j+1}-P_i)).Оптимальный алгоритм (Kadane): (O(n)).
Короткое объяснение Kadane:
Поддерживаем максимум подпоследовательности, оканчивающейся в текущей позиции (max_ending), и глобальный максимум (max_so_far). При проходе по массиву обновляем их и запоминаем границы максимального интервала. Работает за (O(n)) и (O(1)) дополнительной памяти.
Реализация (Python): def max_positive_subseq(arr): if not arr: return [] max_ending = arr[0] max_so_far = arr[0] start = best_l = best_r = 0 for i in range(1, len(arr)): x = arr[i] if max_ending + x >= x: max_ending += x else: max_ending = x start = i if max_ending > max_so_far: max_so_far = max_ending best_l, best_r = start, i return arr[best_l:best_r+1] if max_so_far > 0 else []
Краткая альтернатива (если не требуется вернуть сами индексы, только сумма) — ещё более простая версия Kadane: def max_positive_sum(arr): max_ending = max_so_far = float('-inf') for x in arr: max_ending = max(x, max_ending + x) if max_ending != float('-inf') else x max_so_far = max(max_so_far, max_ending) return max_so_far if max_so_far > 0 else None
Примечание: если нужен возврат непустой подпоследовательности даже при всех отрицательных значениях, можно адаптировать условие проверки и возвращать максимум по сумме независимо от знака.
Ошибки / неэффективности:
Повторный подсчёт суммы среза в цикле: sum(arr[i:j+1]) — это (O(n)) внутри двойного цикла, даёт общую сложность (O(n^3)).Частые вызовы sum(best) в сравнении (ещё дополнительная трата времени).Присваивание best = arr[i:j+1] копирует срез (ещё затраты на память/время).Поведение при пустом массиве и при всех неположительных элементах формально корректно (возвращает []), но это не документировано.Временная сложность:
Оригинальный код: (O(n^3)).Простое улучшение с префиксными суммами: (O(n^2)) (предвычислить (P), где (S(i,j)=P_{j+1}-P_i)).Оптимальный алгоритм (Kadane): (O(n)).Короткое объяснение Kadane:
Поддерживаем максимум подпоследовательности, оканчивающейся в текущей позиции (max_ending), и глобальный максимум (max_so_far). При проходе по массиву обновляем их и запоминаем границы максимального интервала. Работает за (O(n)) и (O(1)) дополнительной памяти.Реализация (Python):
def max_positive_subseq(arr):
if not arr:
return []
max_ending = arr[0]
max_so_far = arr[0]
start = best_l = best_r = 0
for i in range(1, len(arr)):
x = arr[i]
if max_ending + x >= x:
max_ending += x
else:
max_ending = x
start = i
if max_ending > max_so_far:
max_so_far = max_ending
best_l, best_r = start, i
return arr[best_l:best_r+1] if max_so_far > 0 else []
Краткая альтернатива (если не требуется вернуть сами индексы, только сумма) — ещё более простая версия Kadane:
def max_positive_sum(arr):
max_ending = max_so_far = float('-inf')
for x in arr:
max_ending = max(x, max_ending + x) if max_ending != float('-inf') else x
max_so_far = max(max_so_far, max_ending)
return max_so_far if max_so_far > 0 else None
Примечание: если нужен возврат непустой подпоследовательности даже при всех отрицательных значениях, можно адаптировать условие проверки и возвращать максимум по сумме независимо от знака.