Признак в условии
- «сумма подмассива», «сколько подмассивов с суммой X»
- много запросов «сумма на отрезке» к неизменному массиву
- есть отрицательные числа, из-за которых окно не годится
Идея
pre[i] - сумма первых i элементов. Тогда сумма отрезка [l, r] равна pre[r+1] − pre[l] за O(1). Для подсчёта подмассивов с нужной суммой храним частоты префиксных сумм в Map.
Шаблон
const seen = new Map([[0, 1]]); // пустой префикс встречался один раз
let sum = 0, count = 0;
for (const n of nums) {
sum += n;
count += seen.get(sum - k) || 0;
seen.set(sum, (seen.get(sum) || 0) + 1);
}
Сложность
Время O(n), память O(n).
Частые ошибки
- забыт начальный ноль в Map - теряются подмассивы, начинающиеся с первого элемента
- попытка решить окном при наличии отрицательных чисел
- off-by-one в границах: сумма [l, r] это pre[r+1] − pre[l], а не pre[r] − pre[l]
Мнемоника
«Разность префиксов - это отрезок»
Не путать с
- Скользящее окно - префиксы нужны, когда участок может быть любым и числа бывают отрицательными; окно - когда сумма монотонно растёт при расширении
- Хеш-таблица - префиксы почти всегда работают в паре с хеш-таблицей: она хранит «какой префикс уже встречался»
Задачи на этот паттерн
- префиксные суммы
- число подмассивов с суммой k
- точка равновесия
- произведение всех, кроме себя
- подмассивы, делящиеся на K