Про приключения с алгоритмами и LeetСode
Alexey Bykov, Google Developer Expert for Android
В прошлом году я занимался решением задач на LeetCode в течение четырех месяцев каждый день и хочу поделиться своей историей, с надеждой на то, что она поможет кому-то еще.
Зачем?
Давайте будем честны: в мобильной разработке, для большинства задач, с которыми мы сталкиваемся ежедневно, знания, по типу «обход графа в ширину, aka BFS» или «в глубину, aka DFS» не приносят практической пользы. Для небольшой части оставшихся задач (с которыми вы, возможно, не столкнетесь на протяжении всей вашей карьеры), эти знания можно освоить по мере необходимости. (например, мемоизация активно используется в Jetpack Compose «под капотом»).
В моем случае, я изучал алгоритмы исключительно для успешного прохождения будущих собеседований с алгоритмической секцией в крупных зарубежных компаниях и для того, чтобы чувствовать себя увереннее и безопаснее на международном рынке в случае неожиданного сокращения, т.к. в то время, я работал по Skilled Worker Visa в Великобритании и был привязан к работодателю.
Учёба
Прежде чем бросаться в изучение важно понять, как делать это эффективнее. Мне сильно зашёл подход, чем-то схожий со Spaced Repetition, который подразумевает повторение изученного материала с постепенно увеличивающимися интервалам. Вот как это выглядело для меня:
- Первый день изучения
Изучаем новую концепцию, ведём конспект, разбираем базовую практику. После, оставляем эту концепцию на 1-3 дня, уделяя следующие дни новым концепциям - После перерыва
Делаем упор на практику и выходим за пределы стандартных примеров. Обновляем конспект. Постепенно увеличиваем интервалы, возвращаясь к теме
Один из моих знакомых так же вставлял в этот подход конспектирование от руки в первый день, а затем переносил в Notion/Obsidian, опираясь на исследования.
План
Все предыдущие мои попытки «подружиться» с LeetСode не увенчались успехом, во многом, из-за отсутствия плана. Я просто открывал случайную задачу и пытался её решить. В этот раз, я потратил значительное время на изучение того, «а что вообще нужно изучать» и постепенно пришёл к такому списку:

Как вы можете заметить, я сознательно пропустил ряд тем, таких как динамическое программирование, битовые операции и некоторые алгоритмы обхода графов, вроде Дейкстры, поскольку не хотел затягивать этот процесс дольше, чем на 3-4 месяца, т.к. удовольствия от решения подобных проблем я не получаю. Моя конечная цель заключалась в том, чтобы научиться решать большинство задач уровня Medium по указанным выше темам за 20-30 минут, создавать +/- компилируемое решение и успешно находить ошибки.
Как проходила учёба
Легко почувствовать разочарование, когда не можешь решить задачу уровня «easy» на протяжении 3-4х часов. Тем более, если это продолжается изо дня в день, лишь с небольшим прогрессом.
Первый месяц был просто ужасным, в плане того, как именно я себя чувствовал в попытках решать задачи подобного типа. Неоднократно посещали мысли в стиле «надо бросать», «я недостаточно умён для этого», «только одарённые люди способны решать такие задачи».
Постоянство
Одним из самых важных аспектов при изучении нового материала является регулярность. Лучше заниматься по «немного», но каждый день (или только по будням), чем раз в неделю по 10 часов. В моем случае, я учился каждый день, включая выходные, в среднем по 4-10 часов, совмещая это с работой. Стоит ли вам делать так же? Я бы не рекомендовал. Я дошел до того, что решал задачи в день операции под наркозом и на следующий день после. Это был не самый разумный шаг. Моя эффективность на работе также снизилась.

Если бы я проходил через этот процесс снова, я бы рассмотрел следующие варианты:
- Уволиться, уделяя все те же 4-10 часов в день, но только в будние дни.
- Перейти на part-time, уделяя не более 4 часов в день, тоже в будние дни
- Сменить команду (большую часть времени я работал в платформенной команде с фокусом на Developer Experience, где каждая задача требовала изучения чего-то нового. Написание фич давалось мне намного легче)
- Сменить работу на ту, где нет сложной специфики, если сменить команду невозможно
Подходы и паттерны
Раньше я просто случайным образом переходил к задачам на Leetcode, что было неэффективно. В этот раз я решил сосредоточиться на паттернах, на которых строятся решения к каждой задаче. Со временем я начал их замечать практически в каждой задаче, что позволило сделать неплохой прогресс.
В пике мне удавалось решать по 6 задач в день (в среднем я решал 0-2).Во многом это стало возможным благодаря списку Grind 75: да, чтобы ознакомиться со всеми возможными темами, которые могут спросить вас, достаточно решить всего 75 задач.
Для меня лично несколько задач для освоения концепции было недостаточно. У Grind есть сортировки и фильтры, которые помогли мне сосредоточиться на правильных задачах:

У Grind 75, так же есть хорошая альтернатива — NeetCode 150.
Также рекомендую вести таблицу, где вы будете документировать каждую задачу, которую решаете, так как это может помочь закрепить ваше понимание и облегчить повторное изучение материала в будущем. Вот пример того, как выглядит моя таблица:

Я бы отметил, что не стоит запоминать решение. Запоминайте подход к решению, и со временем «клик» обязательно придет. Обратите внимание, что некоторые задачи в принципе не могут быть решены без знания определенных подходов. Если за несколько часов у вас нет прогресса в решении, можно посмотреть на решение и вернуться к задаче через несколько дней с новыми силами.
Альтернативные источники
Далеко не каждый день я решал задачи на LeetCode, поскольку многие вещи я просто не мог понять, читая объяснения решений задач или подходов.
Я также активно решал задачи на AlgoExpert (на мой взгляд, там одно из самых лучших видеообъяснений) и Coderforce (там в основном олимпиадные задачи, но есть огромное количество легких задач, которые легче, чем «easy» уровень на LeetCode). Я часто использовал такие задачи как «разминку» перед решением более сложных.
Я бы рекомендовал начинать именно с Coderforce, а затем переходить на LeetCode. Бывало и такое, что я не понимал тему, которую изучал, ни на одном из вышеперечисленных источников.
В таких случаях мне помогали такие YouTube-каналы, как Nick White и Neetcode.
Мок-интервью
Со временем, я стал созваниваться с друзьями, где мы вместе решали задачи на время.
Мы использовали структуру интервью, которой следует бОльшая часть компаний, когда проводит секцию с алгоритмами:
- Представление / IceBreaker (5m)
Во время интервью интервьюер обычно рассказывает об этапах процесса интервью и представляет себя в течение 2-х минут.
Затем вы должны рассказать о себе в течение 1-2 минут. Я советую включить в этот рассказ ваше самое значимое достижение, измеряемое в цифрах.
В некоторых случаях, интервьюер может спросить вас что-то техническое, не больше behavioral-уровня: например о задаче, которая была для вас наиболее сложной. Это не происходит так часто на этапе алгоритмической секции, но это может случиться на интервью в крупных IT-компаниях. Важно помнить, что главная цель таких вопросов на этом этапе — снять напряжение с вас. Не стоит тратить более 2-х минут на ответы, так как у вас еще будет 1-2 задачи - Первая задача (15m)
В большинстве случаев, идет уровень «easy» или легкий «medium». Интервьюер может зачитать задачу устно. Я рекомендую перехватить инициативу и начать задавать уточняющие вопросы. Главной целью является полное понимание входных и выходных данных, а также выявление всех возможных edge-кейсов до того, как вы начнете писать решение - Вторая задача, aka Follow up (15-20m)
Интервьюер может дать новую задачу, но очень часто он модифицирует первую задачу и добавляет новые требования. Данная задача обычно сложнее предыдущей, но правила игры те же - Вопросы от вас (5m)
Подготовьте их заранее. Например, мне очень нравится спрашивать о текущих KPI, над чем работает интервьюер в данный момент, какие самые крутые задачи ему приходилось решать, работая на текущей позиции.
Чему я научился на мок интервью
- Уточнять требования к задаче. Они очень часто даны расплывчато — это отличный шанс, чтобы проявить себя
- Объяснять, как мой код будет работать перед тем, как его написать
- Проверять решение перед сдачей, самому находить проблемы и оперативно исправлять их
- Не выходить за пределы тайм слота
Всего, я провел около таких 40 мок интервью. (Рекомендую сразу делать это на английском языке). Есть так же платформа Pramp, где вы можете бесплатно практиковаться
Как проходили собеседования
В процессе обучения всегда кажется, что вы еще не полностью подготовлены. Однако, если вы успешно проходите все мок-интервью, то вероятнее всего, вы готовы. Пробуйте! Если вам не повезет, то вы можете попробовать еще раз через полгода-год. Не все зависит только от вас, настроение и интерес интервьюера, как и языковой барьер, так же легко могут влиять на результат
Как проходило у меня
Я проходил алгоритмические интервью в разных компаниях четыре раза, и каждый раз это был уникальный опыт.
В одном случае я считал, что прошел секцию идеально — решил задачу и ответил на все вопросы, объяснив все нюансы и подводные камни. Я даже закончил интервью раньше запланированного времени. Однако, обратная связь была неоднозначной — интервьюеру не понравилось, что я не предложил более оптимальное решение быстрее. Несмотря на это, я прошел на следующий этап.
В другом интервью я даже не смог решить задачу до конца (она связана с динамическим программированием, что я не особо изучал). Я думал, что это автоматически означает отказ, но мне дали довольно позитивную обратную связь и пригласили на следующий этап.
В третьем случае я решил задачу, но не смог решить follow-up вопрос. Сразу после интервью я понял, как нужно было решить задачу. Но и в этом случае мне так же предложили пройти на следующий раунд.
Перед интервью
- Берите day off/отпуск на день интервью. Наличие разного контекста может сыграть ключевую роль в вашей внимательности к задаче
- Если вы чувствуете сильную усталость и что вы не готовы сегодня писать код при ком-то — перенесите интервью. Отмены/переносы происходят повсеместно, это никак не повлияет на ваши шансы
- Решите 2-3 задачи за 2-3 часа до интервью, чтобы разогреть мозг и переключиться в нужный режим работы. Старайтесь выбирать легкие задачи, чтобы не перегружать себя и не создавать дополнительного стресса перед интервью
- Я рекомендую не изучать ничего нового в день интервью, так как это может негативно повлиять на ваше физическое и моральное состояние. Эти знания вряд ли отложатся в постоянную память, и вы не сможете глубоко обсуждать их с интервьюером. Лучше фокусироваться на том, что вы уже знаете, и не перегружать свой мозг перед интервью
В заключение
Решение таких задач может быть сложным, но не стоит забывать, что большинство людей чувствуют то же самое. Важно понимать, что эти задачи разработаны с целью вывести вас за границы своей зоны комфорта. Так же неважно, как хорошо или плохо у вас с математикой (на 1-м курсе техникума меня чуть не исключили из-за неё) — всё зависит только от наличия хорошего плана, упорства, хорошего баланса и постоянства. Постарайтесь, так же, не сравнивать свой прогресс с прогрессом других людей: например, один мой знакомый, потратил месяц, чтобы добиться такого же прогресса, как я за 4 и это абсолютно нормально.
Я продолжу описывать свой опыт с собеседованиями вот тут: @invalidate_cache