Блог

Как пользоваться Литкодом?

Один из самых популярных сайтов для подготовки к техническим собеседованиям — leetcode.com. Там собрана неплохая база задачек на разные темы, но, чтобы получить максимальную пользу от их решения, желательно иметь четкую структуру. Мы разработали конкретный алгоритм подготовки, если просто следовать ему, вы увидите свой прогресс. Он работает не только с литкодом, но и с любой другой базой задач.

Данный алгоритм подходит не на всех этапах. Он предназначен для тренировки, чтобы "набить руку" или вспомнить, как проходить собеседования после перерыва, когда базовые знания уже есть, но существуют проблемы со скоростью, тестированием или с выбором алгоритма. (Этап закрепления). Если вы не уверены, какой сейчас этап, можно попробовать позаниматься по этой инструкции, и если часто приходится смотреть в ответ, значит сейчас лучше переключиться на этап обучения: пройти курс по алгоритмам, изучить теорию, а также не смотреть ответы, а долго думать над каждой задачей, чтобы подход лучше запомнился. Через некоторое время можно возвращаться к тренировке по этой инструкции. По необходимости повторять цикл несколько раз.

0. Создаем таблицу для результатов.

Со следующими полями: 
problem, date, time to accepted, attempts, checked tags, checked solution, learn more?
Можете скопировать нашу.

Почему именно такие поля, и как их заполнять, будет понятно дальше. 

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

1. Выбираем случайную задачу.

На Литкоде можно перейти по этой ссылке: https://leetcode.com/problems/random-one-question/all
Если пользуетесь другой базой задачек, поищите там такую функцию. На крайний случай закрываем глаза и тыкаем наугад.
Почему важно именно случайную? Это похоже на реальное собеседование: там может попасться что угодно, и никто не скажет: это задача на хэш-таблицы. Распознавать, что за задача — это тоже важный навык. Также желательно скрыть сложность задач (она не всегда соответствует действительности и только мешает), для этого есть расширение в Хроме

2. Ставим таймер и начинаем решать.

Таймер можно поставить на телефоне или часах и положить так, чтобы его было видно.
Все уведомления на телефоне должны быть отключены, как и на компьютере.
Неважно, что попалось. Нельзя пропускать задачи. Если что-то хочется пропустить, надо решать с удвоенной силой. Почему может не хотеться решать? Если что-то сложное, надо все равно пытаться, не сдаваться сразу. Если что-то простое или что уже решенное, то можно написать за 5 минут, невелика потеря. Навык написать с первого раза даже что-то понятное надо тренировать. Единственное исключение: если такая задача попадалась сегодня, то можно не решать.

3. Придумываем решение.

Если прошло 10 минут, и до сих пор ничего не понятно, смотрим теги (на Литкоде открываем плашку Related Topics). Должно натолкнуть на идеи. Но не открываем ее до того, как прошло 10 минут! Дайте себе подумать.

Нельзя писать код, пока в голове не сложилась четкая картинка будущего решения. Со всеми деталями. Если используется map, то чем будут ключи, а чем значения? Если рекурсия, то какое условие выхода? И т.п. Можно ходить по комнате, можно рисовать на листочке. Как только решение придумано, записываем два числа в нотации O-большое: сложность по времени и сложность по памяти и переходим к следующему шагу.

Если уж совсем никак, переходим сразу к 6 шагу.

4. Пишем код.

Используем веб-форму, без вашей любимой IDE. Пока не трогаем кнопку Run.

5. Тестирование.

Всё еще не трогаем кнопку Run. Тестируем вручную: придумываем хорошие тест-кейсы, выписываем переменные и их значения и идем построчно, как дебаггер. На реальном собеседовании кнопочки Run не будет!

Как только мы уверены в своем решении, нажимаем сразу Submit. Если неуспешно, делаем пометку и смотрим на упавший тест. Не на всех платформах есть возможность посмотреть, какой тест упал. Даже на литкоде, если тест большой, он не напечатается полностью. В этом случае можно попробовать написать дополнительное решение, которое может быть неоптимально, но с большой вероятностью верно (брутфорс), и с его помощью сгенерировать автоматические тесты для основного решения. 
Далее правим код, пока не станет Accepted, пытаемся уложиться в минимальное количество посылок.

6. Смотрим решение.

Без подписки premium на литкоде не всегда есть доступ к решению от автора, но можно смотреть discussion, там тоже есть решения.

Зачем смотреть решение, если у нас уже Accepted? Полезно рассмотреть разные варианты, если их несколько. Может какие-то проще или быстрее написать, чем ваше. Проверьте, что ваша оценка асимптотики верная. Также иногда удается заслать не самое оптимальное по асимптотике решение. Это нормально. На собеседовании тоже может быть успешным не самое оптимальное решение, если оно без ошибок. Тем не менее, в таких случаях желательно переписать ваше решение на оптимальное и перезаслать его.

7. Повторная посылка.

Неважно, либо мы не смогли решить задачу, либо решили перепослать более оптимальное решение, нельзя копировать ответ или переписывать, глядя на него.
Итак, мы убедились, что поняли решение. Закрываем вкладку с ответом.
И пишем полностью из памяти, как в пунктах 4-5, стараемся послать за наименьшее количество попыток. Иногда только реализовав самостоятельно, понимаешь детали, которые ускользают, если только посмотреть на код.

8. Заполняем таблицу.

problem: ссылка на задачу
date: дата решения
time to accepted: (мин) останавливаем таймер как только послали первый accepted. Если так и не удалось решить, ставим inf и отмечаем в learn more topic, что надо подучить
attempts: считаются все запуски кода, в том числе если не удержались от кнопки Run
checked tags: yes, если открывали плашку related topics, иначе no
checked solution: no, если первый accepted был до того, как увидели ответ, иначе yes
learn more topic: добавляем сюда всё, что надо подучить. Например, плохо идут задачи с графами, значит пишем graphs. Если в ответах упоминается DSU, а вы не знаете, что это, значит пишем DSU.

9. Рефлексия.

Каждые 10 задач стоит остановиться и проанализировать результаты.
Если в колонке checked solution более 10% задач, стоит пока остановиться, посмотреть на колонку learn more topic и поработать над пробелами: пройти релевантные курсы (например, наш!), почитать книги или посмотреть видео/статьи. Порешать задачи более медленно. И только потом возвращаться. Если слишком часто смотреть в ответы, то пользы не будет, нужно пытаться сокращать checked solution до нуля.

Напутствие

Здесь, как и в любом деле, важна стабильность. Лучше решать всего по одной задачке каждый день, чем "пока мне некогда, но вот когда-нибудь в будущем я сяду и решу сразу много!". Можно повесить календарь и зачеркивать крестиком каждый день, в котором была решена хотя бы одна задача. Постараться, чтобы цепь из таких крестиков не прерывалась! Через некоторое время вы заметите, что числа в колонках time to accepted и attempts уменьшаются, а checked solution стремится к нулю.

С помощью регулярных занятий вы научитесь:
- находить решение в сжатые сроки
- использовать нужные структуры данных
- оценивать алгоритмы по асимптотике
- быстро и правильно писать код 
- тестировать вручную и видеть ошибки без компилятора

Это всё очень важные навыки для прохождения собеседований, но их, к сожалению, недостаточно. Какие еще нужны навыки, и как их отработать, рассмотрим в следующий раз.


Памятка для решения каждой задачи


0. Поставить таймер (не забыть остановить после accepted)
1. Определяемся с решением и записываем O(N) по времени и по памяти.
2. Если нет идей за 10 минут, смотрим теги.
3. Если нет идей за хотя бы 30 минут, переходим к шагу 6 (если часто возникают трудности, мы с радостью поможем вам подтянуть алгоритмическую базу).
4. Пишем код.
5. Отлаживаем вручную.
6. Смотрим решения.
7. Если понравилось чужое решение, переписываем его по памяти и отправляем.
8. Заполняем таблицу.
Если количество решенных задач кратно 10:
    9. Рефлексия.


Разработка