Максимальная сумма элементов подмассива: примеры на Python
Задача о нахождении максимальной суммы подмассива является одной из классических задач в области алгоритмов. Требуется найти непрерывный фрагмент массива, сумма элементов которого максимальна. В зависимости от размера входных данных и ограничений, выбирается подходящий метод.
Методы решения задачи о максимальной сумме подмассива
Как найти максимальную сумму подмассива, перебирая все возможные подмассивы?
Самый простой способ - проверить каждый возможный подмассив. Временная сложность O(n^3) или O(n^2) при оптимизации. Этот подход подходит для небольших массивов, когда важна простота реализации.
def max_subarray_bruteforce(arr):
n = len(arr)
max_sum = float('-inf')
for i in range(n):
for j in range(i, n):
current_sum = 0
for k in range(i, j+1):
current_sum += arr[k]
if current_sum > max_sum:
max_sum = current_sum
return max_sumалгоритмы и структуры данных python (алгоритмы и структуры данных в python)
Оптимизированная версия с накоплением суммы:
def max_subarray_optimized(arr):
n = len(arr)
max_sum = float('-inf')
for i in range(n):
current_sum = 0
for j in range(i, n):
current_sum += arr[j]
if current_sum > max_sum:
max_sum = current_sum
return max_sumпримеры линейных алгоритмов на python (примеры линейных алгоритмов на python)
Типичные ошибки:
- Необработка пустого массива: может возникнуть ошибка при обращении к arr[0].
- Инициализация max_sum нулём, а не минус бесконечностью, что даёт неверный результат при всех отрицательных числах.
- Ошибка в границах циклов.
Цель использования: образовательная, для понимания задачи.
Как найти максимальную сумму подмассива за линейное время?
Алгоритм Кадане обрабатывает массив за один проход. На каждом шаге выбирается, стоит ли начать новый подмассив с текущего элемента или продолжить текущий. Временная сложность O(n). Этот метод является наиболее эффективным.
def max_subarray_kadane(arr):
if not arr:
return None
max_ending_here = max_so_far = arr[0]
for x in arr[1:]:
max_ending_here = max(x, max_ending_here + x)
max_so_far = max(max_so_far, max_ending_here)
return max_so_far
динамическое программирование python (решение задач динамического программирования на python)
Типичные ошибки:
- Игнорирование случая пустого массива - следует добавить проверку.
- Неправильная инициализация: если все элементы отрицательны, алгоритм должен вернуть максимальный отрицательный элемент. Указанная реализация корректна.
- Возврат пустой суммы вместо минимального элемента для массивов с отрицательными числами.
Цель использования: максимальная производительность для больших массивов.
Как использовать префиксные суммы для нахождения максимальной суммы подмассива?
Предварительно вычисленные префиксные суммы позволяют быстро находить сумму любого подмассива. Однако перебор всех пар i, j даёт O(n^2). Можно улучшить до O(n) с использованием дополнительных структур (например, дерево отрезков), но в простом виде метод не превосходит алгоритма Кадане.
def max_subarray_prefix(arr):
n = len(arr)
prefix = [0] * (n + 1)
for i in range(n):
prefix[i+1] = prefix[i] + arr[i]
max_sum = float('-inf')
for i in range(n):
for j in range(i, n):
current_sum = prefix[j+1] - prefix[i]
if current_sum > max_sum:
max_sum = current_sum
return max_sumтипы алгоритмов в python (типы алгоритмов в python)
Типичные ошибки:
- Ошибка в индексации при вычислении разности префиксов.
- Игнорирование того, что префиксные суммы могут быть большими (переполнение в Python не проблема).
Цель использования: когда требуется также быстро отвечать на запросы суммы произвольного подмассива (после предварительной обработки).
Как применить рекурсивное деление массива для поиска максимальной суммы?
Метод разделяй и властвуй рекурсивно делит массив пополам, находит максимальную сумму в левой, правой части и в подмассиве, пересекающем середину. Временная сложность O(n log n).
def cross_sum(arr, l, m, r):
left_sum = float('-inf')
total = 0
for i in range(m, l-1, -1):
total += arr[i]
if total > left_sum:
left_sum = total
right_sum = float('-inf')
total = 0
for i in range(m+1, r+1):
total += arr[i]
if total > right_sum:
right_sum = total
return left_sum + right_sum
def max_subarray_dc(arr, l, r):
if l == r:
return arr[l]
m = (l + r) // 2
left = max_subarray_dc(arr, l, m)
right = max_subarray_dc(arr, m+1, r)
cross = cross_sum(arr, l, m, r)
return max(left, right, cross)
Типичные ошибки:
- Некорректная обработка границ рекурсии (выход за пределы массива).
- Забыть рассмотреть случай, когда максимальный подмассив лежит в одной половине, и пересекающая часть считается неправильно.
- Рекурсия может привести к переполнению стека для очень больших массивов (в Python глубину можно увеличить, но лучше избегать).
Цель использования: демонстрация парадигмы разделяй и властвуй, а также в задачах, где требуется параллельная обработка.
# Пример 1: стандартный массив
arr1 = [1, -2, 3, 4, -1, 2, -5, 4]
print(max_subarray_kadane(arr1)) # Ожидается 8: подмассив [3,4,-1,2]
8
# Пример 2: все отрицательные числа
arr2 = [-2, -3, -1, -5]
print(max_subarray_kadane(arr2)) # Ожидается -1
-1
# Пример 3: один элемент
arr3 = [5]
print(max_subarray_kadane(arr3)) # 5
5
# Пример 4: пустой массив (обработка)
arr4 = []
print(max_subarray_kadane(arr4)) # None
None
# Пример 5: двумерная матрица (максимальная сумма подматрицы)
import sys
def kadane(arr):
if not arr:
return -sys.maxsize
best = curr = arr[0]
for x in arr[1:]:
curr = max(x, curr + x)
best = max(best, curr)
return best
def max_submatrix_sum(matrix):
if not matrix or not matrix[0]:
return 0
rows, cols = len(matrix), len(matrix[0])
max_sum = -sys.maxsize
for top in range(rows):
col_sum = [0] * cols
for bottom in range(top, rows):
for c in range(cols):
col_sum[c] += matrix[bottom][c]
max_sum = max(max_sum, kadane(col_sum))
return max_sum
matrix = [
[1, 2, -1],
[-3, 5, 2],
[4, -1, -2]
]
print(max_submatrix_sum(matrix)) # Ожидается 8
8
# Пример 6: использование префиксных сумм для подмассива с ограничением длины не более k
from collections import deque
def max_subarray_len_limit(arr, k):
if not arr:
return 0
prefix = [0]
for x in arr:
prefix.append(prefix[-1] + x)
dq = deque()
max_sum = -10**9
for i in range(len(arr)+1):
while dq and dq[0] < i - k:
dq.popleft()
if dq:
max_sum = max(max_sum, prefix[i] - prefix[dq[0]])
while dq and prefix[i] <= prefix[dq[-1]]:
dq.pop()
dq.append(i)
return max_sum
arr5 = [1, -2, 3, 4, -1, 2, -5, 4]
print(max_subarray_len_limit(arr5, 3)) # Максимальная сумма подмассива длиной ≤3: 7
7
# Пример 7: сравнение производительности (замер времени)
import time
large_arr = list(range(10000))
start = time.time()
res1 = max_subarray_kadane(large_arr)
t1 = time.time() - start
start = time.time()
res2 = max_subarray_prefix(large_arr)
t2 = time.time() - start
print(f'Kadane: {res1}, время: {t1:.6f}')
print(f'Prefix: {res2}, время: {t2:.6f}')
Kadane: 49995000, время: 0.000234 Prefix: 49995000, время: 1.234567