Хабр, привет! Меня зовут Владимир Михайлов, я занимаюсь бэкендом в Яндекс Технологиях — мы создаём внутренние продукты, которые используют в разных юнитах Яндекса. Также я работаю наставником на курсах «Разработчик C++» и «C++ для бэкенда» в Яндекс Практикуме. 

А ещё я помогаю компании с наймом и провожу предварительные секции с кандидатами — разработчиками C++. Я расскажу, какие задачи даю на этих секциях, на что обращаю внимание и как подготовиться к подобному собеседованию.

Что такое предварительные секции

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

Первый из них — предварительные секции — провожу, в том числе, я. У меня есть час в Zoom, чтобы дать кандидату задачи, посмотреть на то, как он их решает, и задать дополнительные вопросы. Потом я оставляю фидбек о потенциальном сотруднике для следующего нанимающего специалиста. Я пишу, решил ли кандидат задачи и ответил ли на вопросы, насколько уверенно это сделал. Также делаю заметки о его софтскилах: насколько корректно он общался и сильно ли нервничал (особенно актуально для тех, кто впервые проходит такие секции).

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

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

Первая задача: простая, но не совсем

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

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

Программа принимает массив с числами nums и переменную k, равную максимальному возможному расстоянию между одинаковыми значениями. Если условия выполняются — равные числа в nums есть и разница их индексов меньше или равна k, код должен выдавать true, если нет, то false.

Или вот — задача на выявление повторяющихся последовательностей символов в строке.

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

Неожиданно, но на первой задаче люди застревают чаще всего. Хоть она и кажется очень простой и такой, в определённом смысле, является, но иногда её не могут решить и опытные разработчики. Есть такое состояние: думаешь, что всё сделал и предусмотрел, но тут тебе задают каверзный вопрос, и ты «плывёшь». Тут то же самое: кажется, что код написан и вроде всё работает, но внезапно всплывает какой-то айсберг и всё — ступор. Самое долгое решение на моей памяти заняло 55 минут из часа встречи. 

Вторая задача: алгоритмы

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

Пример c Leetcode — решение математического примера, записанного обратной польской записью.

На входе мы получаем массив из чисел и операторов. Код должен выдать результат решения.

Ещё один пример — задача про заправки.

Мы едем по круговой трассе с заправками. На каждой заправке i мы заливаем в бак gas[i] бензина, а доезжая до неё, тратим cost[i] бензина. На входе мы получаем массивы gas и cost, цель — узнать, с заправки с каким индексом нужно начать движение, чтобы объехать круг один раз, или вернуть -1, если это невозможно.

Похожие примеры есть в «Тренировках по алгоритмам» от Яндекса — бесплатном курсе с лекциями, домашними заданиями и разборами ошибок.

Если остаётся время

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

Также я могу задать человеку вопросы по теории. Спросить про умные указатели, многопоточность и асинхронность (что это такое, чем они отличаются и как они связаны), контейнеры (зачем нужен array, если есть vector?) и так далее. Но это необязательная часть интервью — всё-таки решение задач хорошо закрывает эти базовые вопросы, так как человек использует функции, контейнеры. Без знания теории у него ничего не получится.

На что я обращаю внимание

Есть несколько критериев, которые влияют на мою оценку кандидатов.

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

Даже незнание функций не является чем-то непоправимым. Может, человек идёт на минимальный грейд? В таком случае я уточню, что кандидат — потенциальный стажёр.

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

#include <iostream>
 
bool func(vector<int>& v) { // тут плохи непонятные название функции и параметра + то, что параметр передаётся по ссылке, а не по константной ссылке (но это зависит от задачи)
...
    for(int i = 0; i < v.size(); i++) // тут плохо сравнение signed и unsigned (со всеми вытекающими)
    {
    }
    ...
    int some_params;
    ...
    some_params++; // нет смысла использовать постфиксный инкремент в этой ситуации
....
}

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

Рассуждения. Если кандидат рассуждает вслух, прекрасно. Если нет, тоже ничего страшного, так как он всё равно проговорит решение, а я смогу задать дополнительные вопросы. Грамотное рассуждение важнее, чем решенная задача, — иногда человек правильно мыслит, проговаривает корректное решение, но не может полностью реализовать его в коде. Стоит отметить, что речь не об абсолютной неспособности решить задачу — скорее, я могу закрыть глаза на то, что кандидат не реализовал нужную, но не самую важную функцию. И если останется время, мы всё равно к ней вернёмся. Чаще всего подобные ошибки у разработчиков случаются из-за волнения, и это нормально.

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

Главный вопрос, который я задаю себе в конце каждого интервью: а хочу ли я видеть этого человека в команде? Если нет, то это главный и единственный красный флаг — я напишу об этом в итогах встречи и опишу, что именно мне не понравилось. При этом мой вердикт не будет однозначным NO HIRE, я просто поделюсь впечатлениями с рекрутером. Если честно, такие кандидаты мне ещё не встречались.

Как подготовиться к предварительным секциям в Яндексе

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

В подготовку я бы включил час в день на Leetcode. Когда готовился к найму, решал две задачи Easy и одну Medium. Если понимал, что задача не даётся за 15 минут, искал готовое решение и пытался его понять и реализовать. Если вы уверенно решаете эти задания и можете решить за час две задачи Medium, то можете попробовать Hard. Но в собеседованиях такой уровень обычно не встречается.

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

«Тренировка по алгоритмам» от Яндекса будет с вами строже — вы поймёте, что код не работает, но вам придётся самостоятельно разбираться почему. Это может сильно бесить, но это полезно.

Также полезно повторять общую теорию — например, те же вопросы о типах контейнеров встречаются во многих подборках «Популярные вопросы на собеседовании по С++».

Комментарии (24)


  1. bromzh
    01.07.2024 09:47
    +4

    к сожалению, я не могу поделиться реальным примером

    к счастью, уже есть статьи с реальными задачами!
    https://habr.com/ru/articles/779538/
    https://habr.com/ru/articles/550088/


  1. NightShad0w
    01.07.2024 09:47
    +8

    А какие типовые задачи с LeetCode для Lead или Principal Software Engineer вы предлагаете на собеседовании?

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

    В Яндексе рабочие задачи должны решаться с первого раза?

    Кто в производственном процессе выполняет декомпозицию бизнес-требований до задач уровня LeetCode с описанием входных и выходных данных и лимитов по ресурсам?


    1. kozlov_de
      01.07.2024 09:47
      +1

      Lead или Principal Software Engineer должен хорошо знать system design, software architect

      А эти задачки ему... Ну я бы предложил сделать ревью по решению задачи.

      А ещё лучше: "предоставьте что вы набираете мидлов и синьоров, какие вопросы вы будете задавать?"


  1. Sazonov
    01.07.2024 09:47
    +8

    Году в 2015 собеседовался в Яндекс в Минске на C++ backend. Перед собеседованием всем давали простенькую задачу на кольцевые списки, видимо чтобы отсеять совсем уж джунов.

    Собеседование длилось 2 часа (секции по часу), после чего меня развернули. До вопросов по программированию мы даже не дошли.

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

    Но я до сих пор не понимаю, каким образом эти «собеседования» показывают умение писать код на плюсах. Ладно бы, если бы меня собеседовали на разработчика алгоритмов для навигации (к примеру), но я бы сам на такие позиции не подавался.


    1. qwerty228327
      01.07.2024 09:47
      +1

      Яндекс - начальник, ты - дурак


  1. iboltaev
    01.07.2024 09:47

    Первая задача действительно простая, решается через std::unordered_map<int, std::set<int>>, O(N*logK)

    Вторая неожиданно сложная, хоть и easy. На ум приходит суффиксный массив + sliding window за O(NlogN), но это чет не easy

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


    1. wataru
      01.07.2024 09:47

      Вторая задача - уровня easy. Там можно наивно решать. А так, есть решение за O(n): строка периодическая тогда и только тогда, когда префикс функция от строки не короче n/2 и n-pi(n) делит n.


    1. wataru
      01.07.2024 09:47

      Да и первая решается, если хочется бытсро, за O(n). Заводим unordered_set и складываем туда числа в окне длиной k. Перед складыванием сморим, а есть ли там уже такое число. Число на позиции i-k удаляем.


    1. vityo
      01.07.2024 09:47


      1. wataru
        01.07.2024 09:47

        Фи, вставлять код скриншотом. Хабр даже в подстветку синтаксиса имеет.


    1. vityo
      01.07.2024 09:47

      Там o(n)


      1. wataru
        01.07.2024 09:47

        Зачем повторяете? И опять скриншотом. У вас ctrl-c, ctrl-v не работает?

        Я про это решенгие выше, кстати, уже написал.


  1. Serpentine
    01.07.2024 09:47
    +3

    Есть несколько критериев, которые влияют на мою оценку кандидатов.

    <...>

    Стиль кода.

    Я, конечно, в Яндекс не попаду и так, но тут вы перегибаете, на мой взгляд. Человек мог долго работать с другим стилем, типа Plan 9 style (может её и разрабатывал), переучиться этому много ума не требуется. Так можно и за не/перенос на новую строку фигурных скобок человека срезать.

    Вот несколько типичных ошибок:

    // тут плохи непонятные название функции и параметра + то, что параметр передаётся по ссылке, а не по константной ссылке (но это зависит от задачи)

    Это, на секундочку, лайф-кодинг, человек в стрессе может находится, тогда как придумывание названий функциям на неродном языке требует другой обстановки. Лучше уж условные foo() и bar(), чем puzyrek_sort() и krutitDerevo().

    // тут плохо сравнение signed и unsigned (со всеми вытекающими)

    Это больше не к стилю относится, а к непониманию что такое преобразование типов и переполнение.

    // нет смысла использовать постфиксный инкремент в этой ситуации

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


    1. lleri Автор
      01.07.2024 09:47
      +1

      С моей точки зрения, стиль кода - это повод поговорить (и выяснить, где непонимание, а где просто спешка или нервы), а не повод отказать, если что.


  1. coodi
    01.07.2024 09:47
    +4

    Супер, отлично. Но как эти задачи связаны с С++?


  1. coodi
    01.07.2024 09:47

    // тут плохо сравнение signed и unsigned (со всеми вытекающими)

    Тут плохо, что сравниваются два разных типа - int и size_type


  1. eptr
    01.07.2024 09:47
    +2

    for(int i = 0; i < v.size(); i++) // тут плохо сравнение signed и unsigned (со всеми вытекающими)

    Тут плохо, в первую очередь, потенциальное UB от возможного переполнения int.
    А также, даже если заменить int на unsigned, от возможного бесконечного цикла на распространённых 64-битных системах, потому что size_type для вектора обычно совпадает с std::size_t, который там длиннее unsigned.

    some_params++; // нет смысла использовать постфиксный инкремент в этой ситуации

    Равно как и префиксный.

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

    Предварительные секции помогают проверить общие знания кандидата по С++

    Это собеседование — не по C++, а по решению алгоритмических задач.
    А C++ просто используется как язык реализации, то есть, он второстепенен на этом собеседовании, причём собеседующий легко может не заметить UB в коде.


    1. wataru
      01.07.2024 09:47

      Это собеседование — не по C++, а по решению алгоритмических задач.

      А что, было бы лучше проходить опросник по основам языка? Типа: чем отличается lvalue от rvalue, как делается наследование, в каком порядке идут аргументы у std::set::lower_bound, дайте определение UB?

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

      А тут кандидату придется написать какой-то осмысленный код на 5-10 строчек.


      1. coodi
        01.07.2024 09:47
        +3

        Да, лучше. Не опросник, а примеры использования, рассказать про них. А тут не осмысленный код получается, а примеры из литкода, реализация которых не зависят от языка программирования


      1. dv0ich
        01.07.2024 09:47
        +3

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


      1. eptr
        01.07.2024 09:47
        +1

        А что, было бы лучше проходить опросник по основам языка? Типа: чем отличается lvalue от rvalue, как делается наследование, в каком порядке идут аргументы у std::set::lower_bound, дайте определение UB?

        Почему опросник?

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

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

        Вот, например, неплохой тест, где как раз имеются примеры кода на понимание языка, правда, этот тест явно не на Junior'а, вопреки названию (обещают, что тест проживёт только до конца недели).

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

        Также можно дать фрагменты кода на review, типа того же самого, что уже обсуждалось, чтобы далеко не ходить:

        for(int i = 0; i < v.size(); i++) 

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

        Тут же есть повод спросить, каким может быть тип выражения v.size(), и чем он может определяться (это уже для более высокого уровня владения, и если это вообще может быть нужно по работе).

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

        О вещах, типа lvalue и rvalue тоже — либо сам расскажет, либо они "подвернутся под руку" при обсуждении какого-либо фрагмента кода, и тогда уже сам собеседующий опять может позадавать дополнительные вопросы, но не про коня в вакууме, а на примере конкретного фрагмента кода.

        По наследованию тоже можно фрагмент дать и побеседовать предметно.

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

        Тогда это будет собеседование по C++, а не по умению решать алгоритмические задачи, причём, собеседование, максимально приближенное к тому, чем человеку придётся заниматься.

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

        Да мало ли кто что использует.

        Цель-то — в чём?
        Сотрудника нанять или формально по какому-то опроснику пройти?

        А тут кандидату придется написать какой-то осмысленный код на 5-10 строчек.

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

        В реальности, если собеседующийся станет сотрудником, он никогда не будет этого делать в таком виде.


        1. wataru
          01.07.2024 09:47

          Цель-то — в чём?Сотрудника нанять или формально по какому-то опроснику пройти?

          Отсеять "плохих" кандидатов в первую очередь. А во вторую отделить хороших кандидатов от отличных. потому что если у вас 10 человек на одно место, то парочка весьма сильных кандидата все равно должны быть отсеяны.

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

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

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

          В реальности, если собеседующийся станет сотрудником, он никогда не будет этого делать в таком виде.

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


  1. togame
    01.07.2024 09:47
    +1

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

    2. Как он понимает из алгоритмических задач, что у интервьюируемого есть опыт с умными указателями?

    3. Если надо готовиться за неделю, то я не буду готовиться неделю. За это время работу новую можно и с 5 провести собеседований.

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


  1. togame
    01.07.2024 09:47

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

    2. Как он понимает из алгоритмических задач, что у интервьюируемого есть опыт с умными указателями?

    3. Если надо готовиться за неделю, то я не буду готовиться неделю. За это время работу новую можно и с 5 провести собеседований.

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


  1. togame
    01.07.2024 09:47

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

    2. Как он понимает из алгоритмических задач, что у интервьюируемого есть опыт с умными указателями?

    3. Если надо готовиться за неделю, то я не буду готовиться неделю. За это время работу новую можно и с 5 провести собеседований.

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