Паттерны решения задач

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  ← Ошибка найдена!
 

Простой тест сразу показал баг


Как встроить в процесс

  1. Написал код — не радуйся сразу
  2. Придумай 2-3 простых теста — такие, где ответ очевиден
  3. Проверь — совпадает ли вывод с ожиданием
  4. Если не совпадает — ищи ошибку, добавь print() внутрь цикла
  5. Если совпадает — добавь граничные случаи (пустой список, один элемент)
  6. Всё ок? — теперь подавай реальные данные

Это и есть мышление программиста

Профессионал не доверяет своему коду, пока не проверит. Даже опытные разработчики делают ошибки — разница в том, что они ловят их до того, как код уйдёт в продакшн

Привычка проверять гипотезы на простых данных:

  • Экономит время на отладку
  • Даёт уверенность в решении
  • Помогает понять, что именно делает твой код

Глава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"]
 

Но на этапе обучения лучше делать по шагам — так меньше ошибок и легче отлаживать


Типичные комбинации паттернов

ЗадачаПаттерны
Найти сумму подходящих элементовФильтрация → Накопление
Получить имена активных пользователейФильтрация → Трансформация
Найти самый дорогой товар в наличииФильтрация → Поиск экстремума
Проверить валидность и посчитатьПроверка всех → Накопление
Сгруппировать и найти макс в каждой группеГруппировка → Поиск экстремума

Советы по решению комбинированных задач

  1. Разбей на части. Прочитай задачу и выдели глаголы: “отфильтровать”, “посчитать”, “найти максимум” — это твои паттерны.
  2. Решай последовательно. Сначала сделай первый паттерн, проверь результат через print(). Потом второй.
  3. Не оптимизируй сразу. Два цикла подряд — это нормально. Сначала сделай правильно, потом можно объединить.
  4. Называй промежуточные переменные понятно. filtered_users, active_orders, total_sum — так легче отлаживать.
  5. Проверяй на маленьких данных. Возьми 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