Мои советы относятся в основном к решению задач на структуры данных и алгоритмы (DSA) на тренажёрах типа LeetCode и Codewars. Примеры кода — на Python. Пункты ниже я собрал по собственному опыту собеседований и решения задач на этих платформах.

1. Решайте Easy-задачи

При любом обучении нужно следить за кривой сложности. Medium-задачи требуют уверенного знания базовых алгоритмов, иногда — сочетания нескольких алгоритмов. Hard — вообще задачи олимпиадного уровня. На собеседовании вам дадут задачу уровня Easy или Medium. Браться за Medium и просидеть весь вечер, уставившись в экран, чтобы потом спросить ChatGPT, — такая себе подготовка. Easy поможет твёрдо усвоить синтаксис, базовые структуры данных и самые частые алгоритмы. Смело сортируйте список задач по уровню сложности и старайтесь решать их поступательно и регулярно. Далее сложность можно повышать, когда будете готовы.

Отсортированный по сложности список задач на LeetCode проще для учебы
Отсортированный по сложности список задач на LeetCode ��роще для учебы

2. Решайте задачи повторно

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

Список всех ваших попыток решений хранит детали о дате попытки, времени работы, памяти и прочие заметки
Список всех ваших попыток решений хранит детали о дате попытки, времени работы, памяти и прочие заметки

3. Смотрите чужие решения

Например, вы решили задачу в лоб. Она выполняется быстрее, чем 50% других решений. Если у вас нет больше идей для рефакторинга, откройте чужое решение. Там вы можете узнать о более эффективном алгоритме. Вам будет проще его понять, потому что вы глубоко разобрались в предложенной задаче. Это лучше зубрёжки алгоритмов по безликим сайтам и видео. Заодно вы натренируете насмотренность и чтение кода, а также добавите пару приёмов в свой арсенал. Иногда к решениям даже видео прикладывают.

У лучших решений высокий рейтинг, ценные комментарии и даже видео с объяснениями.
У лучших решений высокий рейтинг, ценные комментарии и даже видео с объяснениями.

4. Решайте в лоб

Это вполне рабочий подход на собеседовании. На всех тренажёрах кода новички так и решают задачи. Да, спустя месяц-два уже появляется спортивный интерес: начинает хотеться писать красивый, быстрый, эффективный код. Но во время собеса на решение «по красоте» нужно тратить дополнительное время. Я у себя замечал, что буквально можно попасть в ступор, пока из головы достаёшь, как там устроен stack или как правильно двигать sliding window. Не забывайте, что на собеседованиях важнее всего задачу решить, а уж потом отрефакторить. Экономьте время: делайте грязно, но делайте.

5. Гуглите

На собесе можно гуглить. За это не ругают. На крайний случай, можете попросить разрешение и вам в 99% случаев разрешат. Вы можете гуглить документацию, синтаксис, шпору для какого-нибудь алгоритма, подсказку с какой-нибудь табличкой/диаграмкой (попробуйте без подсказок вспомнить как привести десятичные числа в двоичную систему и обратно). В отдельных редких случаях разрешают и LLM пользоваться. Главное, не гуглите решение к задаче, тут ваш собес внезапно завершится.

6. Используйте особенности разных типов данных

Реализация разных типов данных даёт вам разные ключи к решению задач. Строки в Python, например, можно итерировать, разворачивать, конкатенировать и слайсить, как и списки. Наборы убирают дубли. Словари можно использовать как хранилище частот, индексов и любой другой информации для целого ряда задач (это часто называют hashmap-подходом). Поиск по словарю выполняется за O(1), в отличие от поиска по списку за O(n). Учите основные методы структур данных и преобразовывайте их друг в друга, чтобы получать доступ к более эффективным инструментам.

Например, вам нужно посчитать частоты букв в слове, можно использовать словарь:

def count_letters(sentence: str) -> int:
	...
	
	freq = {} # Словарь (hashmap) удобно использовать для подсчётов, отметок,
			  # что мы уже встречали значение, повторного поиска и т. д.
	
	for letter in sentence:
		if letter not in freq:
			freq[letter] = 1 # Заполним маппинг с частотами всех букв за O(n)
		else:
			freq[letter] += 1
			
	...
	
	return freq[i] # Поиск частоты любой буквы теперь выполнится за O(1)
  

7. Засекайте время

На собеседовании у вас на решение будет 20–30 минут. Этого времени может быть меньше, если на прошлых вопросах вы задержались, а интервьюер этот момент не модерировал. В стрессовой ситуации у вас может уйти больше времени на восприятие условий задачи. У вас не будет часа на раскачку, как дома, за чашкой кофе с котом на коленках. Ставьте таймер, практикуйтесь решать задачи за эти 20 минут. Потом возвращайтесь к п. 1 и смотрите, сколько заняли повторные решения. На LeetCode есть функция таймера, но можно и на телефоне засечь, конечно.

Время можно просто засечь, либо поставить дедлайн. Таймер останавливается после успешного решения сам.
Время можно просто засечь, либо поставить дедлайн. Таймер останавливается после успешного решения сам.

8. Пишите заметки после выполнения задач

В LeetCode во вкладке Submissions можно оставить заметку. Запишите туда потраченное время, как решили, к каким алгоритмам прибегнули, с чем были затыки. Так вы сможете отслеживать ваш прогресс при повторных решениях.

Вернемся к задаче через неделю и посмотрим, сколько она займет.
Вернемся к задаче через неделю и посмотрим, сколько она займет.

9. Решайте в IDE

На собеседовании могут дать задачу в онлайн-песочнице, а могут попросить решить в IDE. В IDE надо очень быстро ориентироваться: помнить, как написать синтаксис функции с нуля, как её запустить, какой выбрать пакетный менеджер и как им быстро что-то установить. Это всё — ценнейшее время, а также демонстрация ваших навыков. Лучше заранее настроить и запомнить горячие клавиши. Убедиться перед собеседованием, что все команды для настройки окружения запускаются и все пакеты устанавливаются. К тому же, все решенные задачи останутся у вас под рукой. Вы сможете пробегаться по ранее примененным алгоритмам для переиспользования и более детальных разборов. Кстати, в отличие от использования LLM, на автокомплит на собеседованиях смотрят сквозь пальцы 😉. Знаю людей, которые на 50% свой собес так и прошли.

10. Отключите автокомплит во время обучения

Может, противоречивый тейк, но я противник этой фичи для подготовки к собеседованиям (да и вообще для QA). Это лишние колёса на вашем велосипеде: надо учиться ездить самому. Достаточно поискать статьи на тему «джуны разучились кодить из-за LLM» — у проблемы общий корень. Да, удобно и на собеседовании не ругают. Но запоминать конструкции языка фича мешает: вы просто будете жать Tab и смотреть, как за вас работают. Если решать попросят в онлайн-песочнице, вы просто обнулитесь — и привет. Если у вас много лет опыта кодинга, тогда можно оставить, конечно. Но тогда вам и советы мои не нужны.

Автокомплит – удобная, но коварная фича. Дает рыбу, но не учит рыбачить.
Автокомплит – удобная, но коварная фича. Дает рыбу, но не учит рыбачить.

11. Пишите тесты

В песочнице тесты смогут запустить только ваши интервьюеры. У вас есть возможность убить трёх зайцев: устаканить в голове данные на вход и выход, моментально проверять ваше решение и показать на QA-собесе, что вы мыслите TDD-подходом. Вас всё равно, вероятно, попросили бы протестировать вашу функцию, объяснить, как она обработает корнер-кейсы, и т. д. Напишите простых ассертов штуки 2–3 — и сможете за доли секунды себя проверять.

# Написать пару тестов займет от силы секунд 20, зато вы сможете проверить свое решение и приятно удивить интервьюера.

def test_score_of_five():  
    assert find_rank(score=[5, 4, 3, 2, 1]) == ["Gold Medal", "Silver Medal", "Bronze Medal", "4", "5"]  
  
  
def test_score_of_three():  
    assert find_rank(score=[5, 4, 3]) == ["Gold Medal", "Silver Medal", "Bronze Medal"]

12. Используйте отладчик

Это мощнейший инструмент не только для собесов. Он позволяет видеть стек вызовов, значения на входе функции, что хранится в каждой переменной в любой момент времени выполнения теста (п. 8) и т. д. С отладчиком намного проще найти баг, чем в стрессовой ситуации держать всё в голове и следить, где вы там в цикле находитесь и почему всё время возвращается None. Есть масса туториалов на тему (Документация PyCharm, YouTube). Если не пользуетесь отладчиком, хотя бы пишите в тетрадке.

Научиться отладчику в Pycharm займет десять минут. Дальше с ним вы сэкономите десятки часов.
Научиться отладчику в Pycharm займет десять минут. Дальше с ним вы сэкономите десятки часов.

13. Пользуйтесь тетрадкой

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

14. Выпишите тестовые значения в докстринг

Особенно если вы не пишете тесты — очень удобно, когда перед глазами в самой функции есть значение на вход, ожидаемое значение на выход и ограничения из задачи. Вы можете буквально пальцем по экрану водить туда-сюда — и голова складывает картину, как собрать алгоритм и получить ответ. Я иногда прямо из LeetCode беру условие с примерами и вставляю в докстринг к функции-решению. На собеседовании таких примеров может не быть, и стоит их придумать самому — предварительно уточнив условия и ограничения.

Например, нам нужно написать функцию, которая вернет самые частые числа в списке:

# Держим перед глазами данные на вход и выход
def majority_element(nums: list[int]) -> int:
    """
    Вход: nums = [3,2,3]
    Выход: 3

    Вход: nums = [2,2,1,1,1,2,2]
    Выход: 2

    Ограничения:
    n == nums.length
    1 <= n <= 5 * 10**4
    -10**9 <= nums[i] <= 10**9"""
    ...

15. Изучайте алгоритмы

Некоторые задачи решить своими силами практически невозможно — и это тоже окей. Вам могут потребоваться, например, знания математики, битовых логических операторов, поинтеров (указателей) и других тем, с которыми не сталкиваются QA, AQA и обычные люди. К нерешаемым задачам открывайте список тем, гуглите названия оттуда, разбирайте на примерах, применяйте, делайте пометки. Не просто так собеседования для разработчиков называют «алгоритмами», а не просто «лайв-кодингом».

# Функция должна находить в списке число без дубля.
def single_number(nums: list[int]) -> int:
    xor = 0
    for num in nums:  
        xor ^= num # Вместо перебора с подсчётом в словаре можно использовать XOR.
                   # Дубли "схлопнутся", останется единственное число.
                   # О сценариях применения XOR редко узнают из бытовой жизни —
                   # это нужно специально изучать: смотреть подсказки, чужие решения и т. д.
  
    return xor

16. Начните с базовых алгоритмов

Вот список, на мой взгляд, самых частых и полезных алгоритмов, на которых строятся основные задачи уровня Easy и частично Medium. Объяснять их в рамках этой статьи невозможно, просто перечислю: two pointers, hashmap, sliding window, stack, вложенные циклы, цикл while, слайсинг, коллекции itertools и collections, методы вроде dict.get(), index(), keys(), sort(), pop(), append(). Также приложу диаграмму принятия решений, какой алгоритм и когда применять (AlgoMonster).

17. Не учите лишние алгоритмы (хотя бы в начале)

В структуре LeetCode, если идти по порядку или браться за Explore-карточки, вам достаточно рано начнут попадаться задачи на связанные списки, бинарные деревья, графы, различные виды сортировок, динамическое программирование, рекурсию. Если у вас есть профильное IT-образование или вы любите темы посложнее, можете в них углубиться (или освежить в памяти). Но на собеседовании QA вас, скорее всего, будут спрашивать про работу со строками, числами, массивами, словарями и комбинаторику. На этом и фокусируйтесь, тратьте время рационально.

18. Обсуждайте решения с LLM

Не решайте с LLM, а именно обсуждайте ваши решения: «Оцени моё решение. У меня не получилось вот это, застрял вот тут — куда дальше копать? Почему тут подходит такое решение, а такое нет?» В таком ключе общаться полезно. Я рекомендую прямо запретить в первых ответах давать вам код, чтобы не было соблазна скопировать и вставить. Ещё можно организовать все ваши запросы по подготовке к лайв-кодингу в один проект, чтобы тот же ChatGPT собирал вам контекст в кучу и не приходилось заново писать промпты.

ChatGPT – хороший наставник, которому можно разрешить давать вам советы и запретить давать вам решения.
ChatGPT – хороший наставник, которому можно разрешить давать вам советы и запретить давать вам решения.

19. Если не решили задачу, говорите, как бы доделали

Когда кончается время на собеседовании, вы можете: а) решить по красоте, б) решить грязновато, в) решить плохо, г) не решить, но быть на пути к решению, д) не решить. В большинстве из этих случаев у вас есть возможность сказать интервьюеру: «Ну вообще тут надо применить то-то и то-то, хотя я и не успел». Покажете ход мысли, волю к победе, что вам не всё равно. Дают бонус в карму за такое.

20. Учитесь на заваленных задачах

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

21. Вырабатывайте рутину

Лайв-кодинг — это стресс. Собесов с лайв-кодингом у вас в карьере, вероятно, будет немного, но ставки на них будут высокими. Чтобы привыкнуть к стрессу, нужно себя в него регулярно погружать. Таймеры, алгоритмы, задачи, свои тесты и лайфхаки — всё это должно быть под рукой, отработанным, предсказуемым. Вам должно стать всё равно, кто там сидит в Zoom и на вас смотрит. Вам поставили задачу — вы спокойно посмотрели, подумали, сделали. Вас не застали врасплох, вы были готовы. Сделайте стресс привычкой — и это перестанет быть стрессом.

Удачи на собеседованиях!