Аннотация: Проблема префиксной суммы и хеш-таблицы всегда была очень запутанной. Я чувствую, что она не очень ясна. Недавно я поделюсь некоторыми похожими проблемами, чтобы помочь вам консолидировать решение проблемы префиксной суммы и хеш-таблицы.
Незавершенные пункты:
- Приведите конкретные примеры;
- Почему бы не использовать «скользящее окно», потому что есть отрицательные числа.
Решение задач | "Ликоу" Задача 560: Сумма является подмассивом K (средний)
Дан массив целых чисел и целое число, нужно найти массив, в котором суммаКоличество последовательных подмассивов .
Пример 1:
输入:nums = [1,1,1], k = 2
输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。
Пример 2:
Input: nums = [1,2,3], k = 3
Output: 2
диапазон данных:
Метод 1: решение грубой силы (тайм-аут)
- Перечислите все смежные подмассивы, а затем определите, равна ли сумма смежных подмассивов
Справочный код 1:
public class Solution {
public int subarraySum(int[] nums, int k) {
int len = nums.length;
int count = 0;
for (int left = 0; left < len; left++) {
for (int right = left; right < len; right++) {
int sum = 0;
for (int i = left; i <= right; i++) {
sum += nums[i];
}
if (sum == k) {
count++;
}
}
}
return count;
}
}
временная сложность:,здесьэто длина массива.
Метод 2: вычислить сумму интервала по «сумме префикса»
- Создавайте массивы сумм префиксов для быстрого вычисления сумм интервалов;
- Обратите внимание, что при вычислении суммы интервалов нижний индекс имеет смещение.
Справочный код 3:
public class Solution {
public int subarraySum(int[] nums, int k) {
int len = nums.length;
// 计算前缀和数组
int[] preSum = new int[len + 1];
preSum[0] = 0;
for (int i = 0; i < len; i++) {
preSum[i + 1] = preSum[i] + nums[i];
}
int count = 0;
for (int left = 0; left < len; left++) {
for (int right = left; right < len; right++) {
// 区间和 [left..right],注意下标偏移
if (preSum[right + 1] - preSum[left] == k) {
count++;
}
}
}
return count;
}
}
временная сложность:,здесьэто длина массива.
Даже если вычисляются суммы префиксов, суммы диапазонов перечисления требуютвременная сложность. Метод оптимизации таков: запоминать некоторую информацию в процессе обхода.
Способ 3: префиксная сумма + хэш-таблица
Поскольку нас интересует только количество раз, а не конкретное решение, мы можем использовать хеш-таблицу для ускорения операции. Так как количество одинаковых сумм префиксов до этого сохраняется, общее количество интервалов не добавляется один за другим, а временная сложность снижается до.
Эту идею нелегко придумать, и необходимо решать больше подобных задач, чтобы медленно взращивать это чувство. Аналогичные вопросы:
- «Лицензионный» вопрос 1: сумма двух чисел;
- «Ликоу», вопрос 1248: Статистика «изящных подмассивов»;
- «Ликоу» Вопрос 454: Сложение четырех чисел II.
Код ссылки 4:
import java.util.HashMap;
import java.util.Map;
public class Solution {
public int subarraySum(int[] nums, int k) {
// key:前缀和,value:key 对应的前缀和的个数
Map<Integer, Integer> preSumFreq = new HashMap<>();
// 对于下标为 0 的元素,前缀和为 0,个数为 1
preSumFreq.put(0, 1);
int preSum = 0;
int count = 0;
for (int num : nums) {
preSum += num;
// 先获得前缀和为 preSum - k 的个数,加到计数变量里
if (preSumFreq.containsKey(preSum - k)) {
count += preSumFreq.get(preSum - k);
}
// 然后维护 preSumFreq 的定义
preSumFreq.put(preSum, preSumFreq.getOrDefault(preSum, 0) + 1);
}
return count;
}
}
объяснить кодpreSumFreq.put(0, 1);
.
Вдумайтесь в смысл алгоритма: после вычисления суммы префиксов текущего числа проверим, сколько сумм префиксов равны текущему числу перед текущим числом.preSum - k
Шерстяная ткань?
Это потому, что удовлетворениеpreSum - (preSum - k) == k
Нас интересует количество интервалов.
Для первого случая перед нижним индексом 0 нет элемента, можно считать, что сумма префикса равна 0, а число равно 1, поэтомуpreSumFreq.put(0, 1);
, что необходимо и целесообразно.
временная сложность:,здесьэто длина массива.