Максимальная сумма элементов подмассива: примеры на 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 глубину можно увеличить, но лучше избегать).

Цель использования: демонстрация парадигмы разделяй и властвуй, а также в задачах, где требуется параллельная обработка.

- квадраты python (вычисление квадратов чисел в python)
- максимальная сумма 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

Максимальная сумма - comments

En
максимальная сумма python (python)