Паттерны решения задач
Tip
Если у тебя уже есть опыт решения задач, (другие ЯП или уже на пайтоне писал что-то) то тебе необязательно делать все из этой темы Можешь попробовать свои силы в решении задач комбинированными паттернами уровня С+ набить руку на синтаксис
Если идет легко - решай сразу сложное. Туго идет сложное - возьми более простое
Рекомендую не использовать ИИ для решения задач
Паттерны ниже опираются на 02.06 - If else и 02.07 - Циклы — если что-то забылось, вернись к этим урокам.
Глава1: Тестирование гипотезы
Первое о чем хотелось бы поговорить перед разбором паттернов решения задач - это о подходе
Note
Тестирование гипотезы: проверяй себя сам
Проблема
Ты написал код. Он не падает с ошибкой. Но работает ли он правильно?
Новички часто попадают в ловушку: код запустился, что-то вывелось — значит всё ок. А потом на реальных данных получается мусор, и непонятно почему
Идея
Прежде чем подавать реальные данные, проверь код на контролируемых данных — таких, где ты заранее знаешь правильный ответ
Это как проверка калькулятора: прежде чем считать сложное выражение, введи 2+2. Если выдаст 4 — можно доверять (не абсолютно, но уже неплохо)
Пошаговый пример разберем
Задача
Написать функцию, которая находит все числа в списке, которые больше среднего значения этого списка
Шаг 1: Пишем код
numbers = [10, 20, 30, 40, 50]
total = 0
for n in numbers:
total = total + n
average = total / len(numbers)
result = []
for n in numbers:
if n > average:
result.append(n)
print(result)
Код не падает, выводит [40, 50]. Но правильно ли это?
Шаг 2: Проверяем на данных, где знаем ответ
Тест 1: Очевидный случай
numbers = [1, 2, 3]
# Среднее = 2
# Больше 2 это только 3
# Ожидаем: [3]
Запускаем — получаем [3] ✓
Тест 2: Все одинаковые
numbers = [5, 5, 5]
# Среднее = 5
# Больше 5 — ничего
# Ожидаем: []
Запускаем — получаем [] ✓
Тест 3: Два элемента
numbers = [10, 20]
# Среднее = 15
# Больше 15 это 20
# Ожидаем: [20]
Запускаем — получаем [20] ✓
Тест 4: Крайний случай — один элемент
numbers = [42]
# Среднее = 42
# Больше 42 — ничего
# Ожидаем: []
Запускаем — получаем [] ✓
Шаг 3: Теперь доверяем
После 4 проверок на простых данных — уверенность выросла. Можно подавать реальные данные из задачи
Какие тестовые данные придумывать?
| Тип теста | Зачем | Пример |
|---|---|---|
| Очевидный случай | Убедиться, что базовая логика работает | [1, 2, 3] — посчитай в голове |
| Пустой ввод | Не падает ли на пустых данных | [] |
| Один элемент | Граничный случай | [5] |
| Все одинаковые | Нет ли ошибки в сравнении | [7, 7, 7] |
| Все подходят | Фильтр не отсекает лишнее | [100, 200, 300] где все > 10 |
| Ничего не подходит | Фильтр не пропускает лишнее | [1, 2, 3] где все < 100 |
| Отрицательные | Работает ли с отрицательными | [-5, -3, -1, 0, 2] |
Пример с ошибкой
Допустим, ты написал код для подсчёта чётных чисел:
numbers = [1, 2, 3, 4, 5, 6]
count = 0
for n in numbers:
if n % 2 == 0:
count = count + 1 # Ошибка: нет отступа!
print(count)
Этот код упадёт с ошибкой. Но что если ошибка тоньше?
numbers = [1, 2, 3, 4, 5, 6]
count = 0
for n in numbers:
if n % 2 == 1: # Ошибка: проверяем нечётные!
count = count + 1
print(count)
Код не падает, выводит 3. Похоже на правду? Но это неправильный ответ!
Проверка гипотезы:
numbers = [2, 4, 6] # Только чётные
# Ожидаем: 3
# Получаем: 0 ← Ошибка найдена!
Простой тест сразу показал баг
Как встроить в процесс
- Написал код — не радуйся сразу
- Придумай 2-3 простых теста — такие, где ответ очевиден
- Проверь — совпадает ли вывод с ожиданием
- Если не совпадает — ищи ошибку, добавь print() внутрь цикла
- Если совпадает — добавь граничные случаи (пустой список, один элемент)
- Всё ок? — теперь подавай реальные данные
Это и есть мышление программиста
Профессионал не доверяет своему коду, пока не проверит. Даже опытные разработчики делают ошибки — разница в том, что они ловят их до того, как код уйдёт в продакшн
Привычка проверять гипотезы на простых данных:
- Экономит время на отладку
- Даёт уверенность в решении
- Помогает понять, что именно делает твой код
Глава2: Простейшие паттерны
Если у вас возникает сложность с решением простых задач, то читаем и решаем этот документ:
https://disk.yandex.ru/i/zfmM_B3CmpbvOA
Глава3. комбинирование паттернов из документа выше (типо продолжение)
Реальные задачи редко решаются одним паттерном. Обычно нужно: сначала отфильтровать, потом посчитать сумму. Или: перебрать, преобразовать, найти максимум. Умение комбинировать паттерны — это и есть алгоритмическое мышление.
Как комбинировать: пошаговый разбор
Задача-пример
У нас интернет-магазин. Есть список товаров. Надо посчитать общую стоимость товаров, которые есть в наличии и стоят дороже 500 рублей.
products = [
{"name": "Наушники", "price": 2500, "stock": 3},
{"name": "Чехол", "price": 300, "stock": 10},
{"name": "Зарядка", "price": 800, "stock": 0},
{"name": "Кабель", "price": 400, "stock": 5},
{"name": "Колонка", "price": 3500, "stock": 2},
]
Шаг 1: Определи паттерны
Читаем задачу по частям:
- “товаров, которые есть в наличии и стоят дороже 500” → фильтрация
- “посчитать общую стоимость” → накопление
Значит нужно: сначала отфильтровать, потом посчитать сумму.
Шаг 2: Реши по частям
Часть 1 — Фильтрация:
filtered = []
for product in products:
if product["stock"] > 0 and product["price"] > 500:
filtered.append(product)
# filtered = [{"name": "Наушники", ...}, {"name": "Колонка", ...}]
Часть 2 — Накопление:
total = 0
for product in filtered:
total = total + product["price"]
# total = 2500 + 3500 = 6000
Шаг 3: Объедини (опционально)
Можно сделать в один цикл:
total = 0
for product in products:
if product["stock"] > 0 and product["price"] > 500:
total = total + product["price"]
Но на этапе обучения лучше делать по шагам — так меньше ошибок и легче отлаживать
Типичные комбинации паттернов
| Задача | Паттерны |
|---|---|
| Найти сумму подходящих элементов | Фильтрация → Накопление |
| Получить имена активных пользователей | Фильтрация → Трансформация |
| Найти самый дорогой товар в наличии | Фильтрация → Поиск экстремума |
| Проверить валидность и посчитать | Проверка всех → Накопление |
| Сгруппировать и найти макс в каждой группе | Группировка → Поиск экстремума |
Советы по решению комбинированных задач
- Разбей на части. Прочитай задачу и выдели глаголы: “отфильтровать”, “посчитать”, “найти максимум” — это твои паттерны.
- Решай последовательно. Сначала сделай первый паттерн, проверь результат через print(). Потом второй.
- Не оптимизируй сразу. Два цикла подряд — это нормально. Сначала сделай правильно, потом можно объединить.
- Называй промежуточные переменные понятно.
filtered_users,active_orders,total_sum— так легче отлаживать. - Проверяй на маленьких данных. Возьми 2-3 элемента, пройди руками — результат должен совпасть.
Задачи на комбинирование
Уровень A: Два паттерна, простые данные
Задача К1 [A]: Сумма положительных
Найди сумму только положительных чисел.
Вход: numbers = [5, -3, 8, -1, 0, 12, -7, 3]
Выход: 28
Задача К2 [A]: Квадраты чётных
Создай список квадратов только чётных чисел.
Вход: numbers = [1, 2, 3, 4, 5, 6]
Выход: [4, 16, 36]
Задача К3 [A]: Длина самого длинного
Найди длину самого длинного слова, которое начинается с гласной.
Вход: words = ["арбуз", "банан", "апельсин", "киви", "ежевика"]
Выход: 8 (апельсин)
Задача К4 [A]: Сколько прошли порог
Посчитай, сколько студентов набрали больше 60 баллов.
Вход: scores = [45, 78, 62, 55, 91, 38, 70]
Выход: 4
Уровень B: Два-три паттерна, словари
Задача К5 [B]: Средний чек активных клиентов Посчитай средний чек только тех клиентов, которые сделали больше одной покупки. Вход:
clients = [
{"name": "Анна", "orders": 3, "total_spent": 4500},
{"name": "Борис", "orders": 1, "total_spent": 800},
{"name": "Вика", "orders": 5, "total_spent": 12000},
{"name": "Гена", "orders": 1, "total_spent": 350},
]
Выход: средний total_spent для Анны и Вики
Задача К6 [B]: Имена топ-покупателей
Получи список имён клиентов, которые потратили больше 1000 рублей.
Вход: тот же список clients
Выход: ["Анна", "Вика"]
Задача К7 [B]: Самый молодой программист Найди имя самого молодого сотрудника с должностью “developer”. Вход:
employees = [
{"name": "Иван", "age": 28, "position": "developer"},
{"name": "Мария", "age": 35, "position": "manager"},
{"name": "Пётр", "age": 24, "position": "developer"},
{"name": "Анна", "age": 31, "position": "designer"},
]
Выход: "Пётр"
Задача К8 [B]: Общий вес доставки Посчитай общий вес посылок, которые нужно доставить сегодня (status = “pending”). Вход:
packages = [
{"id": 1, "weight": 2.5, "status": "delivered"},
{"id": 2, "weight": 1.2, "status": "pending"},
{"id": 3, "weight": 3.8, "status": "pending"},
{"id": 4, "weight": 0.5, "status": "returned"},
]
Выход: 5.0
Уровень C: Абстрактные формулировки, приближённые к реальности
Задача К9 [C]: Кто заработал больше всех в этом месяце? Есть список сотрудников. У каждого есть оклад и список бонусов за месяц. Найди имя того, кто получит больше всех (оклад + сумма бонусов). Вход:
staff = [
{"name": "Алексей", "salary": 80000, "bonuses": [5000, 3000]},
{"name": "Марина", "salary": 95000, "bonuses": [2000]},
{"name": "Дмитрий", "salary": 70000, "bonuses": [10000, 8000, 5000]},
]
Задача К10 [C]: Выведи просроченные задачи Есть проекты, в каждом проекте есть задачи. Выведи названия всех задач со статусом “overdue” из всех проектов. Вход:
projects = [
{"name": "Сайт", "tasks": [
{"title": "Дизайн", "status": "done"},
{"title": "Вёрстка", "status": "overdue"},
]},
{"name": "Приложение", "tasks": [
{"title": "API", "status": "in_progress"},
{"title": "Тесты", "status": "overdue"},
{"title": "Деплой", "status": "pending"},
]},
]
Задача К11 [C]: Проверь корректность заказов Перед отправкой в службу доставки нужно убедиться, что все заказы валидны. Заказ валиден, если: у него есть адрес (поле address не пустое), есть хотя бы один товар, и общая сумма больше 0. Напиши assert, который упадёт, если есть невалидные заказы. Вход:
orders = [
{"id": 1, "address": "ул. Ленина, 1", "items": ["a", "b"], "total": 1500},
{"id": 2, "address": "", "items": ["c"], "total": 500},
{"id": 3, "address": "ул. Мира, 5", "items": [], "total": 0},
]
Задача К12 [C]: Сколько потратил каждый клиент? Есть список заказов. Каждый заказ принадлежит какому-то клиенту. Собери словарь, где ключ — имя клиента, значение — сколько он потратил суммарно. Вход:
orders = [
{"client": "Анна", "amount": 1200},
{"client": "Борис", "amount": 800},
{"client": "Анна", "amount": 650},
{"client": "Вика", "amount": 2100},
{"client": "Борис", "amount": 450},
]
Выход: {"Анна": 1850, "Борис": 1250, "Вика": 2100}
Задача К13 [C]: Найди дубликаты email В системе регистрации нужно проверить, нет ли пользователей с одинаковыми email. Выведи список email, которые встречаются больше одного раза. Вход:
users = [
{"name": "Аня", "email": "anya@mail.ru"},
{"name": "Боб", "email": "bob@gmail.com"},
{"name": "Анна", "email": "anya@mail.ru"},
{"name": "Вика", "email": "vika@mail.ru"},
{"name": "Боря", "email": "bob@gmail.com"},
]
Выход: ["anya@mail.ru", "bob@gmail.com"]
Уровень C+: Сложные сценарии
Задача К14 [C+]: Отчёт по категориям Менеджер просит отчёт: в каких категориях товаров выручка больше 10000? Выручка категории = сумма (цена × продано) всех товаров этой категории. Вход:
products = [
{"name": "iPhone", "category": "phones", "price": 80000, "sold": 2},
{"name": "Samsung", "category": "phones", "price": 60000, "sold": 1},
{"name": "Наушники", "category": "accessories", "price": 5000, "sold": 10},
{"name": "Чехол", "category": "accessories", "price": 1000, "sold": 5},
{"name": "MacBook", "category": "laptops", "price": 150000, "sold": 0},
]
Задача К15 [C+]: Лучший курьер недели Нужно выбрать лучшего курьера. Лучший — тот, у кого больше всего доставок со статусом “completed” и средняя оценка выше 4.0. Если таких несколько — любой из них. Вход:
couriers = [
{"name": "Иван", "deliveries": [
{"status": "completed", "rating": 5},
{"status": "completed", "rating": 4},
{"status": "failed", "rating": None},
]},
{"name": "Пётр", "deliveries": [
{"status": "completed", "rating": 5},
{"status": "completed", "rating": 5},
{"status": "completed", "rating": 4},
]},
{"name": "Сергей", "deliveries": [
{"status": "completed", "rating": 3},
{"status": "completed", "rating": 3},
]},
]
Задача К16 [C+]: Проверь банковские карты Перед проведением платежей нужно провалидировать все карты. Карта валидна если:
- Номер состоит из 16 цифр
- CVV состоит из 3 цифр
- Срок действия не просрочен (формат “MM/YY”, считай что сейчас 12/24)
Выведи список невалидных карт с указанием причины. Вход:
cards = [
{"number": "4111111111111111", "cvv": "123", "expires": "06/25"},
{"number": "5500000000000004", "cvv": "45", "expires": "12/24"},
{"number": "34000000000009", "cvv": "1234", "expires": "03/23"},
{"number": "4222222222222222", "cvv": "789", "expires": "01/26"},
]
Задача К17 [C+]: Рекомендации товаров Нужно порекомендовать пользователю товары. Логика: взять категории товаров, которые он уже покупал, и найти из этих категорий товары, которые он ещё не покупал, отсортировать по популярности (поле “popularity”). Вход:
user_purchases = ["iPhone", "Чехол", "AirPods"]
all_products = [
{"name": "iPhone", "category": "phones", "popularity": 100},
{"name": "Samsung", "category": "phones", "popularity": 80},
{"name": "Pixel", "category": "phones", "popularity": 60},
{"name": "Чехол", "category": "accessories", "popularity": 50},
{"name": "AirPods", "category": "accessories", "popularity": 90},
{"name": "Наушники Sony", "category": "accessories", "popularity": 70},
{"name": "MacBook", "category": "laptops", "popularity": 95},
]
⬅️ Назад: 02.07 - Циклы | Далее: 02.09 - Экзамен ➡️ Модуль: 02 - MOC