Обработка данныхПоследовательности
Алгоритмы · теория и практикаПары и тройки · полный разбор
Пары и тройки в последовательности
Опорные элементы, скользящее окно, подсчёт и агрегация — на примере двоек и троек
1Зачем это нужно
Данные часто приходят длинной последовательностью чисел: показания датчиков, цены, лог событий. Чтобы извлечь полезное, выполняют несколько простых операций: отфильтровать нужные числа, найти опорный элемент, пройти скользящим окном по соседним элементам и что-то посчитать: количество, сумму, максимум, среднее.
Задачи на пары (окно из 2 соседей) и тройки (окно из 3 соседей) решаются по одному и тому же шаблону — меняются лишь условия внутри окна. Разберём оба случая.
| Операция |
Пример |
| Фильтрация |
оставить числа не кратные 5; трёхзначные |
| Опорный элемент |
минимум по модулю; k-й кратный числу m |
| Скользящее окно |
2 соседа (пара) или 3 соседа (тройка) |
| Агрегация |
количество, максимальная сумма, среднее |
2Общий подход
Опорные величины зависят от всей последовательности, поэтому сначала читаем все числа в список, затем считаем опоры, и только потом идём окном.
ШАГ 1
Чтение
Все числа из файла в список a
ШАГ 2
Опоры
Найти опорные значения (N, S и т. п.) по всему списку
ШАГ 3
Окно
Пройти соседние пары/тройки, проверить условия
ШАГ 4
Ответ
Посчитать количество и нужную агрегацию
каркасa = [int(line) for line in open('file.txt')] # шаг 1: число в строке
# шаг 2: опорные значения...
for i in range(len(a) - 1): # пары: -1; тройки: -2
w = a[i:i+2] # окно (для тройки a[i:i+3])
if # условия на окно:
... # шаг 3-4
3Кирпичики: делимость, цифры, разряды
| Нужно |
Как |
| кратно m |
x % m == 0 (0 кратен любому m) |
| не кратно m |
x % m != 0 |
| минимум по модулю |
min(seq, key=abs) |
| трёхзначное |
100 ≤ abs(x) ≤ 999 |
| сумма цифр |
функция ds(x) (см. ниже) |
| округление вниз |
total // count (для положительных) |
сумма цифрdef ds(n):
n = abs(n) # на случай отрицательных
s = 0
while n > 0:
s += n % 10 # последняя цифра
n //= 10 # отбрасываем её
return s
# ds(472) = 13, ds(-900) = 9, ds(100000) = 1
Часть I · Пары (окно из 2 соседей)
4Пары: пример и разбор
Условие. В файле последовательность целых чисел. Пусть N — минимальное по модулю число, не кратное 5. Определите количество пар соседних элементов, в которых оба числа кратны N. В ответе: количество таких пар, затем максимальную из их сумм.
Разбор
Сначала находим N (фильтр «не кратно 5» нужен только для этого). Затем идём по соседним парам и считаем те, где оба элемента кратны N, попутно держа максимум суммы.
парыcand = [x for x in a if x % 5 != 0]
N = min(cand, key=abs) # опорное число
count = 0
best = -10**9 # «минус бесконечность», не 0!
for i in range(len(a) - 1):
if a[i] % N == 0 and a[i+1] % N == 0:
count += 1
best = max(best, a[i] + a[i+1])
print(count, best)
Стартовое значение максимума — −10**9, потому что суммы пар бывают отрицательными; ноль дал бы неверный ответ.
5Интерактив: анализ пар
Выбери последовательность. Программа найдёт N (золотая ячейка), подсветит кратные N (синие) и кратные 5 (серые), снизу отметит соседние пары, где оба кратны N. Над максимальной парой — золотая скоба.
N (опорное) кратно N кратно 5
Анализ парSIM · SWITCHABLE
Данные:
Нажми «сгенерировать» — появится новая случайная последовательность (в ней всегда хотя бы 3 подходящие пары), и N, пары и максимум пересчитаются сами. В примере «суммы < 0» все подходящие пары имеют отрицательные суммы — максимум там отрицательный, а не ноль. Поэтому и нужен старт best = −10**9.
Часть II · Тройки (окно из 3 соседей)
6Тройки: пример и разбор
Условие. Последовательность натуральных чисел. Определите количество троек идущих подряд элементов, для которых: есть хотя бы одно трёхзначное число; не более одного числа с суммой цифр, равной сумме цифр 13-го по счёту элемента, кратного 13; не менее двух чисел с суммой цифр, равной сумме цифр 25-го кратного 25. В ответе: количество троек и среднее их сумм, округлённое вниз.
Разбор
Опорные суммы цифр: S₁₃ — сумма цифр 13-го кратного 13 (это индекс 12 в списке кратных!), S₂₅ — сумма цифр 25-го кратного 25 (индекс 24). Затем по каждой тройке считаем три величины и проверяем три условия.
тройкиS13 = ds([x for x in a if x % 13 == 0][12]) # 13-й → индекс 12
S25 = ds([x for x in a if x % 25 == 0][24]) # 25-й → индекс 24
count = total = 0
for i in range(len(a) - 2):
t = a[i:i+3]
has3 = any(100 <= abs(x) <= 999 for x in t) # ≥1, по модулю
c13 = sum(ds(x) == S13 for x in t) # ≤1
c25 = sum(ds(x) == S25 for x in t) # ≥2
if has3 and c13 <= 1 and c25 >= 2:
count += 1
total += sum(t)
print(count, total // count) # среднее вниз
Сравниваем именно суммы цифр с S₁₃/S₂₅, а не сами числа. И «13-й по счёту» — это индекс 12.
7Интерактив: опора и сканер троек
Сначала потренируйся находить k-й кратный m и его сумму цифр:
k-й элемент, делящийся на mSIM · LIVE
Теперь сканер троек (опорные суммы заданы: S₁₃ = 5, S₂₅ = 7). Двигай ползунок — окно из трёх соседей едет по последовательности, внизу видно выполнение трёх условий.
∑ цифр = S₂₅ = 7 ∑ цифр = S₁₃ = 5 трёхзначное
8Подводные камни
| Ошибка |
Как правильно |
искать трёх- (и др.) значные у отрицательных через 100 ≤ x ≤ 999 |
число берём по модулю: 100 ≤ abs(x) ≤ 999 — иначе −144 не попадёт в трёхзначные |
best = 0 для максимума суммы |
суммы бывают отрицательными → best = −10**9 |
| фильтр «не кратно 5» при подсчёте пар |
он нужен только для поиска N |
взять d13[13] |
13-й по счёту — это индекс 12 |
| сравнивать сами числа вместо сумм цифр |
сравниваем ds(x) с опорной суммой |
| перепутать ≤1 и ≥2 |
«не более одного» = ≤1; «не менее двух» = ≥2 |
| округлить среднее обычным round |
нужно вниз: total // count |
| искать опоры по ходу окна |
сначала весь список, потом окно |
9Полные коды решений
Пары
парыa = [int(line) for line in open('file.txt')]
N = min((x for x in a if x % 5 != 0), key=abs)
count = 0; best = -10**9
for i in range(len(a) - 1):
if a[i] % N == 0 and a[i+1] % N == 0:
count += 1; best = max(best, a[i] + a[i+1])
print(count, best)
Тройки
тройкиdef ds(n): # сумма цифр (см. раздел 3)
n = abs(n); s = 0
while n > 0: s += n % 10; n //= 10
return s
a = [int(line) for line in open('file.txt')]
S13 = ds([x for x in a if x % 13 == 0][12])
S25 = ds([x for x in a if x % 25 == 0][24])
count = total = 0
for i in range(len(a) - 2):
t = a[i:i+3]
if (any(100 <= abs(x) <= 999 for x in t)
and sum(ds(x) == S13 for x in t) <= 1
and sum(ds(x) == S25 for x in t) >= 2):
count += 1; total += sum(t)
print(count, total // count)
10Чек-лист перед ответом
| № |
Что проверить |
| 1 |
Прочитал все числа в список, проверил первые элементы |
| 2 |
Опорные значения нашёл по всему списку (N; S₁₃/S₂₅ — индексы 12 и 24) |
| 3 |
Окно правильного размера: пара (i, i+1) или тройка (i..i+2) |
| 4 |
Условия-счётчики не перепутаны (≥1, ≤1, ≥2) |
| 5 |
Максимум суммы стартует с −10**9, среднее округляю вниз |
| 6 |
В ответе сначала количество, потом агрегат (сумма/среднее) |
11Квиз по файлу
Вопросы ниже — по отдельному файлу quiz.txt (приложен к странице): 600 целых чисел, по одному в строке, среди них есть отрицательные. Глазами столько не перебрать — открой файл и посчитай кодом, затем выбери ответ.
Загрузи файл в Python привычным способом и считай по нему:
a = [int(line) for line in open('quiz.txt')]
Помни про отрицательные: трёхзначные ищем по модулю (
100 ≤ abs(x) ≤ 999), сумму цифр — тоже по модулю.
Вопросы вперемешку: и на пары, и на тройки.
Проверь себя10 задач по файлу