Модуль 8 · Два указателя · ОП.04

Алгоритмы на массивах · модуль 8 · два указателя

Глава 8.3

8.3

Уточняющие вопросы
до решения

В этой главе разобрано, какие вопросы задают интервьюеру до того, как писать код, и что меняет в решении каждый ответ. Основной пример — задача 1 о паре с заданной суммой: её условие уточняется в разговоре с интервьюером. Дальше — вопросы к остальным задачам модуля, общий список для любой задачи на массив и тестовые примеры, которые записывают до кода.

Категория
Работа с условием
Уровень
Начальный
Опирается на
Главы 8.1 и 8.2; занятие 7: вопросы к условию
Зачем это знать
Решать ту задачу, которую поставили, со всеми её крайними случаями

§1Зачем уточнять условие

Условие на собеседовании часто звучит коротко, и часть деталей в нём не названа. В советах кандидатам из журнала Яндекс Образования про это сказано первым пунктом.

«Задавайте вопросы. Задачу могут поставить абстрактно, не уточняя, что в качестве входных данных могут быть, например, отрицательные числа, а вектор может быть пустым… Спрашивайте, что нужно оптимизировать, какие ограничения по времени и памяти нужно учесть при выборе алгоритма».

Для двух указателей вопросы особенно важны: техника работает только при определённых свойствах данных. Если не спросить, отсортирован ли список, можно написать верный по виду код, который на неотсортированном входе пропустит ответ.

У каждого вопроса ниже есть последствие в решении: новая строка кода, граница цикла или тест. Вопросы о легенде задачи, после которых в решении ничего не меняется, можно не задавать.

§2Разговор с интервьюером о задаче 1

Слева — условие задачи 1 в том виде, в каком его произнёс интервьюер. Справа — вопросы, которые можно задать. После каждого вопроса в разговоре появляются ответ интервьюера и то, что этот ответ меняет в решении, а под условием слева — новое уточнение. Порядок вопросов любой.

Задача 1 · пара с заданной суммой
условие от интервьюера

«Цены товаров в каталоге отсортированы. Есть подарочный сертификат на сумму target. Найдите два товара, которые вместе стоят ровно эту сумму».

уточнено

    §3Что меняет каждый ответ

    После разговора условие становится точным, и его можно записать как контракт функции: что она принимает, что возвращает и чего не делает со входом. В таблице для каждого ответа указано, какую часть решения он определяет.

    Ответ интервьюераКуда попадаетЧто это значит для решения
    Цены по возрастаниюВыбор способаПо порядку видно, какую цену можно отбросить, поэтому перебор всех пар не обязателен
    Товар нельзя взять дваждыГраницы поискаПара — два разных номера, i < j
    Пары нет — NoneРезультатВторой исход функции, у него свой тест
    Каталог может быть пустымТестПустой список и список из одного товара дают None
    Память O(1), вход не меняетсяОграничение на способНи копии, ни словаря, ни sorted(); тест проверяет, что список после вызова тот же
    Вернуть индексыФормат результатаПара номеров (i, j), сортировать копию нельзя
    solution.pyконтракт после уточнений
    def pair_sum(prices, target):
        """Указатели навстречу. Задача 1.
    
        prices — цены по возрастанию, повторы возможны, список может быть пустым.
        Возвращает пару индексов (i, j), i < j, с prices[i] + prices[j] == target,
        или None, если такой пары нет. Список не меняется.
        Время O(n), память O(1).
        """

    §4Вопросы к остальным задачам модуля

    У задач 2 и 3 вопросы другие: они касаются того, что остаётся в списке после вызова и что функция возвращает. Разговор строится так же — каждый вопрос заканчивается изменением в решении.

    ЗадачаВопросТипичный ответЧто меняет
    2 · повторыСписок точно отсортирован?ДаОдинаковые значения стоят рядом: сравнение с последним записанным находит все повторы
    Вернуть число или сам список?Число оставшихсяФункция возвращает длину очищенной части
    Хвост за последним значением нужно убрать?Да, список должен стать корочеПосле прохода лишний хвост удаляется одной операцией
    3 · сжатиеСерию длины 1 записывать с числом 1?Нет, одним символомДлина пишется только у серий из двух и более символов
    Серия длиннее 9 — как писать длину?Каждой цифрой отдельно: 12 → «1», «2»Длина раскладывается на цифры; нужен тест с серией из 12 символов
    Может ли один символ встретиться в двух сериях?Да: «aabaa» → «a2ba2»Серия заканчивается на первом другом символе, счёт не суммируется
    нули в конецПорядок ненулевых сохранять?ДаРешение должно сохранять порядок, перестановки с двух концов не годятся
    Что вернуть?Ничего, список меняется на местеФункция возвращает None, как list.sort()

    §5Общий список для задачи на массив

    Эти вопросы подходят к любой задаче на массив. На собеседовании задают те из них, ответ на которые не очевиден из условия. Порядок в списке — от тех, что меняют выбор техники, к тем, что меняют отдельные строки.

    До кода выяснено

    Порядок данныхОтсортирован ли вход, по возрастанию или по убыванию. От ответа зависит, работают ли указатели навстречу.
    Размер и ограниченияСколько элементов бывает и сколько памяти можно взять. От ответа зависит, проходит ли перебор O(n²) и можно ли завести словарь.
    Можно ли менять входИзменять список на месте или вернуть новый. От ответа зависит, нужны ли указатели чтения и записи.
    Формат ответаИндексы или значения, число или список, одна пара или все.
    Нет ответаЧто вернуть: None, -1, пустой список или исключение.
    Крайние входыПустой список, один элемент, все элементы одинаковые, отрицательные числа, ноль.
    ПовторыБывают ли одинаковые значения и считаются ли они разными элементами.

    §6Тестовые примеры до кода

    Следующий шаг после вопросов — записать несколько входов с ответами. Яндекс в описании секции ставит его первым: «Вместо того чтобы сразу писать код, сначала придумайте тестовые примеры». Примеры проверяют, что условие понято одинаково, и потом превращаются в тесты. Для задачи 1 хватает семи примеров, каждый проверяет свой класс входа.

    pricestargetОтветЧто проверяет
    [300, 450, 700, 900, 1200, 1500]1600(2, 3)обычный случай, пара внутри списка
    [100, 200, 300, 400]500(0, 3) или (1, 2)пар несколько, подходит любая
    [300, 450, 700, 900]100Noneпары нет
    []500Noneпустой вход
    [250]500Noneодин товар: пары нет, хотя 250 + 250 = 500
    [250, 250]500(0, 1)одинаковые цены у разных товаров
    [-7, -3, 0, 2, 9]−1(1, 3)отрицательные числа

    Все семь примеров вошли в tests.py стартового набора. Ответы в таблице получены запуском эталонного решения на Python 3.12.

    §7Проверьте себя

    Вопрос 1Интервьюер ответил: «Каталог может быть пустым». Что из этого следует для решения?

    • Интервьюер назвал этот случай прямо, значит, на нём будут проверять. Функция должна вернуть None и не упасть.

    • Верно. В пустом каталоге пар нет. Этот вход записывают в примеры до кода и проверяют отдельным тестом.

    • Цены уже отсортированы по условию, а пустой список сортировать незачем. Пустой вход влияет только на результат.

    Вопрос 2Какой из вопросов к задаче 1 не меняет ни решения, ни тестов?

    • Меняет границы поиска: пара — только два разных номера, и нужен тест на цену, равную половине суммы.

    • Верно. Это вопрос о легенде: ответ на него не влияет ни на технику, ни на границы, ни на тесты.

    • Добавляет второй исход функции — None — и тест на него.

    • Меняет выбор способа: при миллионе товаров перебор всех пар не проходит.

    Модуль 8 · Два указателя · ОП.04 · 3 курс Автор: Макаров Максим Николаевич