Python Glossary English

все Python 3Алгоритмы и структуры данныхпонятие

Префиксные суммы

техники

Массив prefix[i] = sum(arr[0..i]). Позволяет за O(1) найти сумму на отрезке [l, r].

Синтаксис

prefix[i] = prefix[i-1] + arr[i]
sum(l, r) = prefix[r] - prefix[l-1]

Главная ловушка — сдвиг индексов: если prefix длиной n+1 и начинается с нуля, то сумма отрезка [l, r] включительно равна prefix[r+1] - prefix[l]; без ведущего нуля случай l == 0 приходится обрабатывать отдельно. Техника окупается только на неизменном массиве: правка одного элемента заставляет пересчитывать весь хвост за O(n), и там уже нужно дерево Фенвика или отрезков. itertools.accumulate строит ту же таблицу лениво, но без initial=0 (появился в 3.8) начинает не с нуля, а с arr[0].

Примеры

def build_prefix(arr):
    prefix = [0] * (len(arr) + 1)
    for i, x in enumerate(arr):
        prefix[i+1] = prefix[i] + x
    return prefix
def range_sum(prefix, l, r):
    return prefix[r+1] - prefix[l]
arr = [1,2,3,4,5]
p = build_prefix(arr)
print(range_sum(p, 1, 3))  # → 9 (2+3+4)
arr2 = [3,-1,4,1,5,-9,2,6]
p2 = build_prefix(arr2)
print(range_sum(p2, 0, 7))  # → 11 (вся сумма)
print(range_sum(p2, 2, 4))  # → 10 (4+1+5)
# Количество подмасивов с нулевой суммой
from collections import Counter
def count_zero_sum(arr):
    prefix = 0
    counts = Counter({0: 1})
    result = 0
    for x in arr:
        prefix += x
        result += counts[prefix]
        counts[prefix] += 1
    return result
print(count_zero_sum([1,-1,2,-2,3]))  # → 3 (это [1,-1], [2,-2] и [1,-1,2,-2])
# 2D префиксные суммы
matrix = [[1,2,3],[4,5,6],[7,8,9]]
def build_2d_prefix(mat):
    n, m = len(mat), len(mat[0])
    p = [[0]*(m+1) for _ in range(n+1)]
    for i in range(1,n+1):
        for j in range(1,m+1):
            p[i][j] = mat[i-1][j-1]+p[i-1][j]+p[i][j-1]-p[i-1][j-1]
    return p
p2d = build_2d_prefix(matrix)
print(p2d[-1][-1])  # → 45 (сумма всей матрицы)
# Скользящее окно с prefix
arr3 = [1,2,3,4,5,6,7,8]
p3 = build_prefix(arr3)
k = 3
max_sum = max(range_sum(p3,i,i+k-1) for i in range(len(arr3)-k+1))
print(max_sum)  # → 21 (6+7+8)
# Среднее на подмассиве
print(range_sum(p, 0, 4) / 5)  # → 3.0

См. также

Открыть в полном глоссарииdocs.python.orgСообщить о неточности