Как добиться прогресса, готовясь к интервью по программированию

Перевод статьи Сэма Гэвиса-Хагсона “How to make progress while studying for coding interviews”.

Как добиться успеха на собеседовании

Я обнаружил, что люди, тщательно готовящиеся к интервью, также могут застрять на ровном месте, как и все. А это обидно.

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

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

Когда я работаю с клиентами, они часто находятся именно в такой ситуации. И почти всегда, стоит нам идентифицировать то, что их сдерживает, как у них происходят заметные прорывы. Решение этих проблем дало возможность моим клиентам получить работу в Amazon, Bloomberg, Uber!

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

1. Наработайте сильную основу

Солидный фундамент в виде хорошо усвоенных основ информатики – один из важнейших ключей к успеху на интервью по программированию.

За время моей работы я создал много различных приемов, помогающих моим студентам улучшить их навыки решения задач на собеседованиях. Но ни один из этих приемов не будет иметь смысла, если у вас за плечами нет уверенных знаний основ.

Например, FAST Method создан чтобы помочь студентам с динамическим программированием. Первый шаг этой техники – найти первоначальное рекурсивное брутфорс-решение. Вы должны уметь сделать это самостоятельно, чтобы FAST Method мог быть для вас полезен. Даже если вы понимаете методологию, это вам не поможет, если вы не знаете, как получить начальное решение.

Если у вас есть солидная основа, рекурсия не будет для вас чем-то сложным. Эта тема поднимается достаточно часто, так что вы должны в ней ориентироваться.

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

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

Лучший способ это сделать – пройти курсы по структурам данных и алгоритмам, например от Массачусетского института технологий – MIT (Python) или Принстона (Java). Купите книгу, выполняйте упражнения, сдайте экзамены. Если вы погрузитесь в работу, то легко пройдете курс за 3 месяца или меньше, а потом у вас будет хорошая основа для движения вперед.

Опыт в программировании

2. Получите больше опыта программирования

Вы помните, как пытались сделать что-то впервые? Когда я учился играть на гитаре, у меня уходило 30 секунд на аппликатуру для основного аккорда. Теоретически, я мог бы сыграть любую песню, если бы у меня было достаточно времени, а передо мной были диаграммы аккордов. Но звучало бы это не очень хорошо.

Иногда я работаю со студентами, у которых та же ситуация с программированием. Они просто еще не достигли того уровня, когда смогут с легкостью писать код на собеседованиях.

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

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

Решение здесь одно – просто получить больше практики написания кода. В идеале – в окружении, где вы сможете получить отзывы о своем коде. Один из лучших способов это сделать это принять участие в проектах open source. Это не только отличный способ показать свой опыт. Дополнительными бонусами будут ревью кода и изучение работы в продакшн-среде.

Если у вас нет опыта работы с open source, вам пригодится First Timers Only – отличный ресурс для тех, кто не знает, с чего начать. Там вы найдете инструкции, как принять участие, и список потенциальных проектов, которые подойдут новичкам.

3. Подходите к каждому вопросу собеседования стратегически

У каждого генерала, вступающего в бой с надеждой на победу, есть детальный план. Если вы хотите достичь успеха на своем собеседовании, вам также нужен подробный план.

Чаще всего встречается такой план решения проблем, поставленных в ходе интервью:

  1. Посмотреть на проблему.
  2. Подумать о проблеме.
  3. Выдвинуть идею решения.
  4. Написать решение.
  5. Успех.

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

Именно так большинство людей и думает о задачах на интервью. Они помнят тысячи решений и надеются, что одно из них будет достаточно подходящим для проблемы, с которой они столкнуться на собеседовании, так что решение материализуется магическим образом.

Это как минимум рискованно.

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

[0:00–0:05] Устройтесь и убедитесь, что вы полностью понимаете проблему, которая перед вам стоит. Подумайте обо всех предоставленных вариантах инпута.

[0:05–0:10] Подберите брутфорс-решение. Не пишите код на этом этапе, просто проговорите и нарисуйте что-нибудь, если считаете это полезным. Если вы застряли, попробуйте решить проблему вручную и перевести свой процесс решения в алгоритм.

[0:10–0:15] Оптимизируйте свое решение. Потратьте эти 5 минут на то чтобы найти самое лучшее решение на данный момент. Сравнивая возможные решения, учитывайте сложности со временем.

[0:15–0:35] Напишите код для своего решения. Помните, что лучше иметь законченное неоптимальное решение, чем оптимальное, но не законченное.

[0:35–0:50] Протестируйте свой код и исправьте возникшие проблемы. Это очень важно. Не имеет значения, что ваш начальный код не совершенен, но вы должны уметь находить ошибки.

[0:50–1:00] Вопросы вашего интервьюера.

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

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

Выбор из нескольких вариантов

4. Обдумайте разные варианты решений

Вы знаете, что большинство вопросов на собеседованиях имеют больше одного правильного ответа? Тысячи людей находят решение и останавливаются на нем, прекращая дальнейшие поиски.

Это всегда меня расстраивает. Зачастую, бывает другое, лучшее решение, и они были так близки к нему. Или могли быть варианты решений с разными достоинствами и недостатками.

Например, подумайте над такой проблемой:

Одно решение имеет временную сложность O(n) и пространственную сложность O(1).

Другое решение имеет временную сложность O(log n) и пространственную сложность O(log n).

Какое из решений лучше?

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

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

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

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

5. Начинайте с брутфорс-решения

Я уже упоминал об этом в п.3, но повторюсь. Одна из самых больших ошибок – пытаться решать проблему на собеседовании, сразу подбирая самое оптимальное.

Я спрошу иначе: что лучше, брутфорс-решение или отсутствие решения? Должен сказать, что первый вариант в тысячу раз лучше второго. А если вы сразу начинаете с попытки найти оптимальное решение, то можете легко застрять и в итоге оказаться без законченного варианта.

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

  1. Дает вам путь отступления. Если вы попытаетесь оптимизировать свое решение, но потерпите неудачу, вы можете остановиться через 5-10 минут и просто написать код для брутфорс-решения. Этого может вполне хватить для интервью. Не у всех задач есть оптимальное решение.
  2. Это помогает вам прояснить задачу. Определение брутфорс-решения может помочь вам понять, с чем связано решение этой проблемы. Это ключ. Понимание проблемы на таком глубоком уровне облегчает оптимизацию.

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

Первоначальное брутфорс-решение дает вам ясность и стартовую точку для облегчения всего остального.

Белая доска

6. Планируйте полное решение до того, как начнете писать код

Есть много суперклассных белых досок. Но скорее всего, у той, которую вы будете использовать, не будет copy-paste опции. Это значит, что вам нужно хорошо расположить свой код прежде чем писать его.

Часто люди на собеседовании приступают к написанию кода сразу же, как только им дадут задачу.

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

White board

Хорошая организация на доске удобна и для вас, и для интервьюера. Ему будет легче понять ваше решение, а вам – отследить, что где происходит. Если вы вместо этого решите переписывать код, вы потеряете кучу времени.

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

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

Есть проблемы, где оптимальное решение не имеет ничего общего с брутфорс-решением, и попытки оптимизировать последнее провалятся. Если вы подождете с программированием, то сможете избежать ограничения своего мышления одним взглядом на проблему.

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

7. Помните о картине в целом

Одна из самых больших проблем более опытных разработчиков в том, что они зацикливаются на мелочах. Они начинают обдумывать, лучше ли использовать в цикле < N или <= N, и не могут выбрать.

Это прекрасный пример того, как можно за деревьями не увидеть леса. Они начинают искать ответ на вопрос «Как написать этот цикл правильно?» вместо «Для чего нужен этот цикл в контексте моего кода в целом?».

Отличным примером служит проблема, где вы пытаетесь использовать неправильную структуру данных. Скажем, вы храните переменные проиндексированными с 1-N, и решаете, что хотите использовать HashMap. Вы можете вставить 1 -> value1, 2 -> value2 и так далее.

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

Сейчас вы можете подумать, что никогда не сделаете что-нибудь настолько глупое, но поверьте мне, это происходит постоянно. Когда вы решаете проблему, ваш мыслительный процесс не линейный, так что вы вполне можете решить, что вам нужен HashMap из-за какого-то другого хода мыслей, уже заброшенного.

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

8. Используйте абстракцию как свое преимущество

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

Ключ к успешному решению таких задач в использовании абстракции. Это значит разбить код на меньшие функции с более специфическим назначением.

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

Сделать реверс связанного списка в нашем коде было бы достаточно просто, но что если у нас будет функция, делающая это за нас? Это облегчило бы нам жизнь. Нам только нужно будет вызвать эту функцию, пройтись по всему списку и вывести значения, а затем снова сделать реверс списка, чтобы вернуть инпут в оригинальное состояние.

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

Если перед вами стоит более сложная задача, я советую задать себе вопрос: «Какая функция (если такая есть), облегчила бы мне жизнь сейчас?». Если такая функция существует, пишите ваш код, предполагая ее наличие. Затем, когда остальная часть вашего кода уже будет работать, вы можете вернуться и реализовать эти функции.

В этом есть несколько преимуществ:

  1. Если у вас закончится время, у вас все равно будет в целом работающий код. Абстракция позволяет вам фокусироваться на структуре в целом без риска увязнуть в мелочах. Если у вас есть лишнее время, о мелочах тоже можно позаботиться, но если его нет, то вашему интервьюеру будет понятно, что вы знаете, чего не хватает.
  2. Ясность мышления и написания кода. Говорят, что чистый стол означает чистый ум. С кодом то же самое. Чем лучше организован ваш код, тем легче его обдумывать.

Я думаю, что чем сложнее проблема, тем ценнее может быть разбиение кода на управляемые компоненты.

9. Тестируйте ваш код

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

Одна из таких вещей, о которых люди все время забывают, это тестирование решения на собеседовании. Но разве в реальных условиях вы бы стали коммитить код без его испытания?

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

Ключ тестирования решения в том, чтобы пройтись по коду строка за строкой, отслеживая значения для каждой переменной, и эффективно «запустить» код. Если вы просто читаете код на высоком уровне, вы можете легко пропустить маленькие проблемы в нем. Я записал видео, показывающее, как именно нужно просматривать и тестировать ваш код.

Я знаю, что многие учащиеся испытывают стресс, желая, чтобы их код был совершенным с первого раза. Хотя это хорошее стремление, так бывает редко. В реальном мире такого не бывает практически никогда, так почему же вы думаете, что реально этого добиться в стрессовой ситуации собеседования? Тем не менее, если вы тщательно протестируете ваш код, вы сможете исправить баги и в конечном итоге получить отличное решение.

10. Получайте хорошую обратную связь

Проходить собеседования – лучший способ улучшить свои результаты на них. С приходом опыта вы станете чувствовать себя комфортнее и у вас появится больше возможностей добиться успеха. Часто рекомендуется записаться на большое количество собеседований, причем для начала – в тех компаниях, которые нравятся вам меньше всего. Таким образом вы можете попрактиковаться в условиях, когда не сильно переживаете по поводу результата, а на важном для вас собеседовании у вас уже будет больше опыта.

Я считаю, что у этой стратегии есть свои достоинства, однако имеется и существенный недостаток: компании редко дают вам хорошую обратную связь.

«Не все ли равно? – можете сказать вы. – Я сам буду судить о своих результатах».

Это возможно, но судить о себе довольно тяжело. Вы не знаете, что важно для вашего интервьюера. Есть все шансы, что вы чего-то не заметите, пытаясь добиться успеха.

Вот почему тренировочные интервью (в идеале – с опытным коучем) так важны. Такие интервью позволяют вам получить подробные отзывы о том, как вы себя показали. Интервьюер может также указать вам на вещи, которые ускользнули от вашего внимания.

Если вы серьезно подходите к процессу собеседований, я также советую тренироваться с наставником. Интервью это своеобразные срезы, они показывают вам, что по данному вопросу в данный период времени вы показали хороший или плохой результат. Наставник может систематизировать полученные данные и помочь вам увидеть то, над чем вам нужно поработать.

Я постоянно вижу людей, застрявших в ходе собеседования. И почти всегда это происходит по какой-то из причин, описанных выше. Если вы никак не можете добиться желаемого прогресса, прочтите эту статью внимательнее. Определите, в чем у вас проблема, и работайте над ее устранением. Со временем вы сможете улучшить результаты своих собеседований и получить звонок, которого ждете.


[customscript]techrocks_custom_after_post_html[/customscript]
[customscript]techrocks_custom_script[/customscript]

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх