Pull to refresh

Comments 51

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

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

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

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

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

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

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

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

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

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

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

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

А ведь один человек из мпс пролез в яндекс. Правда, ненадолго )))

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

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

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

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

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

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

Там o(n)

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

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

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

<...>

Стиль кода.

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

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

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

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

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

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

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

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

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

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

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

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

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 в коде.

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

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

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

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

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

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

А что, было бы лучше проходить опросник по основам языка? Типа: чем отличается 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 строчек.

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

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

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

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

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

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

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

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

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

Мне кажется, Яндекс сравнивать с фаангом - это не совсем корректно - размеры не те.

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

  • У них очереди из кандидатов, потому что:

    • Строчка в резюме работает на HRов как красная тряпка на быка.

    • Зарплаты (считая все бонусы) довольно высокие.

    • Яндекс предлагает релокацию.

    • Стандартные плюшки от большой компании: условные "печеньки в офисе".

  • У Яндекса внутри тоже собственная уникальная кухня (потому что их "велосипеды" обычно появились раньше аналогичных распространенных фреймворков) и передовые технологии.

  • У Яндекса, куда не плюнь, везде работа с большими объемами данных, поэтому, уверен, там тоже довольно часто встречаются алгоритмы из литкодовских задач (Более 10 лет назад я там работа удаленно на пол ставки, пока учился. Всякие Trie и хитрые парсеры приходилось применять).

Это вы про что-то типа RnD говорите. В большинстве случаев вы получите среднюю по рынку зарплату, обычные задачи и далёкую перспективу роста. Будете использовать велосипеды из "передовых" отделов и решать текущие проблемы продуктов. Да, и выпускников Яндекса достаточно много, поэтому тряпка не красная, а розоватая, скорее

В большинстве случаев вы получите среднюю по рынку зарплату

levels.fyi говорит, что мидл там получает в среднем 420 тысяч рублей в месяц: https://www.levels.fyi/companies/yandex/salaries/software-engineer/levels/g16. Хабр пишет про 200 тысяч в среднем для москвы: https://habr.com/ru/specials/748058/. Знакомые оттуда не жалуются. Странно, что levels.fyi пишет про мизерный бонус в акциях. Похоже, в связи с концом торгов из-за СВО, весь этот бонус перекочевал в зарплату. Раньше знакомые говорили, что акциями фактически вторую такую же зарплату получают. Возможно из-за этого и пошли слухи про низкую зарплату в яндексе, которые до сих пор не вымерли.

обычные задачи и далёкую перспективу роста

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

Будете использовать велосипеды из "передовых" отделов и решать текущие проблемы продуктов.

Вы вообще не представляете, о чем говорите. Там все используют более менее одни и те же технологии: Фреймворки для фронтенда, системы хранения данных для бека, общие библеотеки вместо stl и boost. Подозреваю, что сейчас с горячкой по AI, там почти любая команда работает с одними и теми же библиотеками по machine learning.

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

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

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

Это-то — в любом случае при таких условиях, независимо от критерия.

Но здесь важен критерий, то есть, — "на что собеседуем", на умение решать алгоритмические задачи или на владение C++ в той мере, в которой это требуется вакансией?

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

Код следует писать, но его следует писать на C++, и в его основе должны быть отнюдь не алгоритмы. В C++ хватает своей специфики, которую обязательно нужно знать, без всяких алгоритмов.

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

Всё уже придумано до нас.

На этом mock-собеседовании на 52 с половиной минуты сначала идёт короткая беседа об умных указателях ("языком болтать"), затем о std::shared_ptr (всё ещё "языком болтать"), а после этого собеседующийся пишет сильно упрощённую, можно сказать, минимально возможную реализацию std::shared_ptr, без проверки компилятором.

В процессе написания он настолько полно раскрывает уровень своих знаний по C++, что кажется, что трудно это сделать лучше, чем это сделал собеседующий с помощью std::shared_ptr и с помощью правильных вопросов по ходу дела.

Заметьте — никаких алгоритмов.

Вот это — настоящее собеседование по C++.
Всего 52 минуты, — а сколько информации получено.

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

Так это же замечательно!

Если долго натаскиваться на умение писать реализацию std::shared_ptr, достичь понимания, что там к чему, что в каких случаях происходит, почему в каких-то местах так, а не этак, где какие сложности и опасности, и как их избегать, какие проблемы и каким способом в различных местах решаются, то так можно и C++ на нужный уровень выучить и научиться на нём писать.

Ровно то, что надо.

Проблема же больших компаний, как всегда, в голове.

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

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

Совместить же одно с другим получается очень плохо: ни то, ни сё.

Так что к яндексу ваш аргумент не очень относится.

То самое mock-собеседование, ссылку на которое я привёл выше, провёл как раз Team Lead из того же Яндекса.

Поэтому думаю, что это — аргумент.

А критерий "хорошести" или "плохости" на чём должен основываться?

Хочется, чтобы человек хорошо и продуктивно работал. Вот только единственный способ 100% это проверить - это испытательный строк. Это запредельно дорого. Поэтому берутся какие-то коррелирующие с этим критерии. Такие, что их относительно легко проверить и относительно легко сделать много разных вопросов по ним.

Заметьте — никаких алгоритмов. (про shared_ptr)

В перечисленных в статье задачах тогда тоже никаких алгоритмов нет. Ну там циклы, условия какие-то. В shared_ptr тоже же какая-то логика. Абсолютно один уровень. У shared_ptr побольше уклон в специфику C++, да, ибо тут надо именно класс написать. Отличный вопрос. Но подобных задач много не придумаешь и если все будут спрашивать про shared_ptr, то вайтишники "с 0 до мидла С++ за 2 месяца" просто выучат его реализацию и сведут до нуля полезность этого вопроса. Ибо его будут отвечать вообще все, а вам все еще надо нанять одного из 10. Произойдет инфляция и спрашивать будут какой-нибудь изврат на вариативных шаблонах. И на хабре все будут плеваться, мол - нафига яндекс эту фигню спрашивает - не надо в реальной жизни писать это. А на интервью в стрессовой ситуации да без любимой IDE это вообще не напишешь.

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

Ну вот как заранее узнать, нужна она там или нет. Я обычный C++ SWE, работаю с хромом. Оказывается тут нужна. Те, кто всякие сервера пишут - там тоже все такое этакое на каждом углу. А вот кто условный BigTable пилит - так там вообще алгоритм на алгоритме, алгоритмом погоняет. Так что это собеседование надо будет вводить для 90+% всех должностей. А если еще учесть, что все гибкое: сегодня команда пишет вот этот проект и тут алгоритмов не надо, а через квартал цели поменялись, проект мутировал и вот уже алгоритмы нужны, то стоит вообще всех SWE по алгоритмам гонять.

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

Хочется, чтобы человек хорошо и продуктивно работал. Вот только единственный способ 100% это проверить - это испытательный строк. Это запредельно дорого. Поэтому берутся какие-то коррелирующие с этим критерии. Такие, что их относительно легко проверить и относительно легко сделать много разных вопросов по ним.

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

Но это и так понятно.

В перечисленных в статье задачах тогда тоже никаких алгоритмов нет.

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

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

У shared_ptr побольше уклон в специфику C++, да, ибо тут надо именно класс написать.

И таких собеседований можно провести больше десятка, но так и не покрыть всего, что есть в C++.

Но подобных задач много не придумаешь и если все будут спрашивать про shared_ptr, то вайтишники "с 0 до мидла С++ за 2 месяца" просто выучат его реализацию и сведут до нуля полезность этого вопроса. Ибо его будут отвечать вообще все, а вам все еще надо нанять одного из 10.

Это же элементарно определяется.

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

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

Произойдет инфляция и спрашивать будут какой-нибудь изврат на вариативных шаблонах.

Где-то, может быть, по глупости, и будут.

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

И на хабре все будут плеваться, мол - нафига яндекс эту фигню спрашивает - не надо в реальной жизни писать это. А на интервью в стрессовой ситуации да без любимой IDE это вообще не напишешь.

Вы сами подсказываете ответ: незачем спрашивать "фигню".
Следует спрашивать то, что максимально проясняет уровень кандидата.

Ну вот как заранее узнать, нужна она там или нет.

В смысле?

Компания ищет сотрудника на конкретную вакансию и не знает, нужна ли там алгоритмическая подготовка, а если нужна, то насколько серьёзная?

Я обычный C++ SWE, работаю с хромом. Оказывается тут нужна. Те, кто всякие сервера пишут - там тоже все такое этакое на каждом углу. А вот кто условный BigTable пилит - так там вообще алгоритм на алгоритме, алгоритмом погоняет.

Видите, всё зависит от позиции.
На какие-то позиции требования — минимальные, на какие-то — максимальные.

Так что это собеседование надо будет вводить для 90+% всех должностей.

Для конкретной компании — возможно.
Получается, что для 10% алгоритмическое собеседование не требуется, а для остальных требуется, но его сложность варьируется.

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

Тогда, как я уже говорил, нужны два собеседования, одно — по C++, другое — по алгоритмам.

А дальше возвращаемся к предыдущим проблемам вот таких C++ интервью - их массово везде не применишь

Это не так, я выше объяснил.

а раз алгоритмы все равно спрашивать надо, то можно их спросить несколько раз.

Вы выше привели пример, когда в компании, в силу специфики разрабатываемых продуктов, алгоритмы нужны.

Но есть и другие примеры.

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

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

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

Ну так во многих задачах с литкода алгоритмов не больше, чем в "напишите shared_ptr".

И таких собеседований можно провести больше десятка, но так и не покрыть всего, что есть в C++.

Ну придумайте-ка хотя бы 5 вопросов. Чтобы они были не очень большие (и сам вопрос не очень длинный и решение можно за 40 минут написать). Чтобы не очень тривиальные (а то это будет та же easy с литкода, где нет специфики C++, а лишь перемешивание функций, циклов да условий в правильной последовательности). А потом представьте, что вам придется придется придумать еще и еще.

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

В сторону, это как? Ну приведите примеры таких вопросов. Какие-то основы да общее представление тоже отлично учится, ибо на этих курсах не просто учат решение одной задачи, а таки натягивают ученика до уровня джуниора. Они даже типы данных помнят, и сколько бит в байте. Вот только написать что-то чуть-чуть не тривиальное без помощи не могут вообще (кроме нескольких заученных вопросов по C++).

Компания ищет сотрудника на конкретную вакансию и не знает, нужна ли там алгоритмическая подготовка, а если нужна, то насколько серьёзная?

Ну вот компания гугл ищет сотрудника на C++ пилить какие-то фичи в хроме, связанные с видео. Практика показала, что алгоритмы нужны. Теперь другой пример: инженер для бакенда на java писать бек какого-нибудь google meet. Нужны алгоритмы, я их сам видел. Еще пример, инженер C++ писать распределенную базу данных над которой крутятся все сервера гугла. Ну тут очевидно нужны алгоритмы. Т.е. компания знает, что любой нанимаемый SWE почти 100% столкнется с алгоритмами в работе, т.е. с ее точки зрения алгоритмическая подготовка нужна.

Тогда, как я уже говорил, нужны два собеседования, одно — по C++, другое — по алгоритмам.

Собеседований нужно несколько. Какие-то надо будет повторить несколько раз. Поскольку собеседования по C++ производить на порядки сложнее (для собеседующих), повторять будут алгоритмические. Вот и пришли практически к существующей ситуации. А дальше, алгоритмические собеседования и так хорошо прореживают входной поток кандидатов, можно и отказаться от дорогого интерьвю по C++. А во время алгоритмического собеседования итак какой-то код на С++ кандидат напишет. Т.ч. если он совсем С++ не знает, это будет видно. А уж если человек способен думать и решать задачки, то выучить синтаксис конструкторов в С++ он точно сможет.

Вы выше привели пример, когда в компании, в силу специфики разрабатываемых продуктов, алгоритмы нужны.

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

Ну так во многих задачах с литкода алгоритмов не больше, чем в "напишите shared_ptr".

Зачем явную неправду говорить?
Здесь же в комментариях люди пишут:

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

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

Ну придумайте-ка хотя бы 5 вопросов. Чтобы они были не очень большие (и сам вопрос не очень длинный и решение можно за 40 минут написать).

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

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

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

Например, берём динамический полиморфизм, как он работает.

Что будет, если вызвать виртуальную функцию, прямо или косвенно из конструктора?

А из конструктора базового класса?

А из конструктора класса где-то в середине цепочки наследования?

Напишите код, демонстрирующий то-то, а потом то-то и то-то из отвеченного на вопрос.

Далее можно спросить, а если код теперь поменять таким-то образом, что произойдёт?

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

Можно продолжить, чтобы понять, насколько досконально человек понимает работу механизма: а если вот здесь взять typeid, то какой тип будет? А почему?

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

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

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

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

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

А что такое structured binding declaration, а при каких условиях оно работает, а напишите пример, а если вот так поменять, то что будет, а почему так, а можете написать range-based loop с использованием structured binding declaration, а кстати, что такое range-based loop, а как из функции вернуть, например, два значения, а не одно, и сразу присвоить его двум переменным, а если переменные уже есть, то тогда как?

А что такое SFINAE, каков принцип его работы, что такое шаблоны, шаблоны чего могут быть, а может ли в шаблоне класса быть шаблон метода, а напишите код в качестве примера, а могут ли шаблонные функции быть виртуальными быть, а что такое инстанцирование, а напишите пример, а что такое специализация, напишите пример, а если вот так поменять, то что будет, а какие виды специализаций бывают (частичная и полная), а напишите пример частичной специализации функции (функции нельзя частично специализировать), тогда пример частичной специализации класса, что такое deduction guide, напишите пример deduction guide, а что такое parameter pack, fold expressions, какие они бывают, а что такое auto, что такое decltype, что такое decltype(auto), а как происходит вывод типов, как происходит разрешение имён, а что такое namespace, а что такое anonymous namespace, а как ими пользоваться, а напишите пример, а где можно и где нельзя объявлять namespace'ы, а что такое user-defined literals, а приведите пример, как они определяются, а какие вы знаете уже определённые в стандартной библиотеке примеры...

А чем отличаются lvalue-reference от rvalue-reference, а каков принцип работы механизма перемещающих конструкторов и assingment operator'ов, в каких случаях он даёт выигрыш, какова суть механизма этого выигрыша, а напишите код демонстрирующий тот и другой случай, а вот если код поменять вот так, то что будет, а почему вместо перемещающего assignment operator'а теперь вызвался копирующий, а каковы требования к типу, чтобы в контейнерах, параметризованных такими типами, вызывались перемещающие, а не копирующие...

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

И это я ещё не затрагивал фишек С++20/23, только C++17, почти не затрагивал библиотеку с её контейнерами, алгоритмами и прочими аллокаторами, итераторами, умными указателями и различными другими вещами.

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

Не затрагивал метапрограммирование на шаблонах.

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

В процессе написания примеров кода обнаружатся другие ошибки

Неужели это всё нужно было расписывать и объяснять?

В сторону, это как? Ну приведите примеры таких вопросов.

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

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

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

Собеседующий спросил об идиоме swap, но кандидат опять оказался не в курсе, о чём речь.

Вот, в чём заключаются "вопросы чуть в сторону".
Вопросы по ходу дела, которые неплохо раскрывают уровень кандидата.

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

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

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

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

Собеседований нужно несколько. Какие-то надо будет повторить несколько раз. Поскольку собеседования по C++ производить на порядки сложнее (для собеседующих), повторять будут алгоритмические. Вот и пришли практически к существующей ситуации. А дальше, алгоритмические собеседования и так хорошо прореживают входной поток кандидатов, можно и отказаться от дорогого интерьвю по C++.

Собеседования нужны ровно те, которые нужны, а не те, которые "дешевле". Цель — сэкономить или нанять нужного кандидата?

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

C++ — не тот язык, где достаточно выучить синтаксис конструкторов и прочие подобные вещи. Слабый в C++ кандидат будет писать код, изобилующий UB, код, не являющийся exception-safe и имеющий прочие недопустимые недостатки.

То есть, нанять слабого по части C++ кандидата может обойтись достаточно дорого.

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

А я и не утверждал, что алгоритмические собеседования не нужны.
Я говорил о том, что собеседование по C++ должно проводиться отдельно от алгоритмического.

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

И соединить это с cache-friendly, потому что сами алгоритмы не в вакууме работают, а также с методами достижения cache-friendly поведения контейнеров, которые по умолчанию ведут себя не cache-friendly.

В сухом остатке:

По крайней мере, одно собеседование по C++, которое — в целом по C++, то есть, без алгоритмов, должно проводиться отдельно.

Часть, связанную с асимптотической сложностью поиска/удаления/вставки для контейнеров стандартной библиотеки, понимания, почему так в каждом случае, а также вопросы, связанные с cache-friendly, скорее всего, придётся проверять отдельным собеседованием, которое похоже на переходное от C++ к алгоритмам.

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

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

Зачем явную неправду говорить?Здесь же в комментариях люди пишут:

Ну вот же в статье даны задачи. В первых двух вообще алгоритмов нет - надо только 2 цикла сделать, чтобы реализовать буквально то, что написано в задаче. Нисколько не хуже shared_ptr. И так во всех easy задачах с литкода, коих там около 25%.

Что будет, если вызвать виртуальную функцию, прямо или косвенно из конструктора?

А из конструктора базового класса?

А из конструктора класса где-то в середине цепочки наследования?

Вот, это те самые вопросы из опросника, о котором я говорил в самом начале.

А чем отличаются lvalue-reference от rvalue-reference

Это практически то, что я приводил в качестве примера.

И от таких опросников люди буду плеваться не меньше: Зачем эту муть из справки учить? Она есть в документации!

Собеседования нужны ровно те, которые нужны, а не те, которые "дешевле". Цель — сэкономить или нанять нужного кандидата?

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

Ну вот же в статье даны задачи. В первых двух вообще алгоритмов нет - надо только 2 цикла сделать, чтобы реализовать буквально то, что написано в задаче.

Неправда.

Если в 219. Contains Duplicate II делать "в лоб", то получается сложность O(n^3), а не O(n), потому что проверка дубликатов "в лоб" делается двумя вложенными циклами, которые дадут O(n^2).

То, что применение std::unordered_set для детектирования дубликатов в скользящем окне вы не считаете алгоритмом — это ваша личная особенность.

Вот, это те самые вопросы из опросника, о котором я говорил в самом начале.

Но проигнорировали дальнейшее мной написанное.

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

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

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

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

Это уже — не опросник, зазубрить не получится, требуется понимать.

Это практически то, что я приводил в качестве примера.

Не знаю, как сейчас, но больше десятка лет назад rvalue-reference'ы объяснялись отвратительно, я удивительно долго не понимал до конца, что там к чему.

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

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

И от таких опросников люди буду плеваться не меньше: Зачем эту муть из справки учить? Она есть в документации!

Если кандидат на вопросы по поводу lvalue и rvalue reference'ов так отвечает, то он сразу не проходит дальше никуда.

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

Соответственно, кандидат не будет знать, где происходит копирование, а где — перемещение.

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

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

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

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

К тому же, масштаб компании слабо коррелирует с глупостью.
Тот же Google умудрился отказаться от исключений в C++.
Более жёсткий ляп трудно придумать.
А сейчас, из-за совместимости, их уже не вернуть назад.

Если в 219. Contains Duplicate II делать "в лоб", то получается сложность O(n^3), а не O(n), потому что проверка дубликатов "в лоб" делается двумя вложенными циклами, которые дадут O(n^2).

Но она же easy! Там достаточно O(nk). Откуда вы там n^3 взяли - ума не приложу. Сокращать до O(n) - не надо, то, что такое сокращение есть, не делает задачу сложной. Так-то и в shared_ptr можно накрутить кастомный аллокатор и там такие заумные алгоритмы полезут, что у кого угодно волосы дыбом встанут. Но это же не делает shared_ptr полным алгоритмов?
И во второй задаче про строки, я почти уверен, что автор задачи даже не знает, что тут можно применить префикс функцию, и подразумевается просто решение в лоб.

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

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

Тот же Google умудрился отказаться от исключений в C++.Более жёсткий ляп трудно придумать.

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

Но она же easy! Там достаточно O(nk). Откуда вы там n^3 взяли - ума не приложу.

Упростил, принял k равным n.

С поправкой на k получается O(nk^2).

C std::unordered_set получается O(n).

Алгоритм такой.

Сначала во множество (std::unordered_set) добавляются элементы, пока их не станет k штук (первый цикл).

Если в процессе добавления обнаруживается, что такой уже есть во множестве, возвращается true.

Затем первый элемент в окне из k элементов удаляется из множества, а следующий за окном добавляется во множество, а окно, таким образом, движется по вектору к его концу, пока окном из k элементов не будет пройден весь вектор (второй цикл).

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

Если до конца массива такого не случилось, возвращается false.

Поскольку операции с std::unordered_set выполняются за O(1), а количество операций равно n, то получается O(n).

Я полагаю, что примерно такое решение должно быть найдено.

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

В данном случае эта подготовка и опыт заключаются в применении hash-table-based множества с хранением там копий элементов, попадающих в окно, что как раз и обеспечивает детектирование этим множеством повторений значений элементов в момент добавления очередного элемента, и hash-table-based множество обеспечивает это детектирование за O(1).

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

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

И точно вызовут отрицательные эмоции у кандидатов.

Вы смеётесь, что ли?
Какие ещё эмоции?

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

В противном случае, он не сможет их решать.

Эмоциональные в этом смысле кандидаты однозначно не подходят.

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

Но такие кандидаты никуда не годятся.

Тут не только понимание, но и заучивание всяких определений и документации. С++ - не самый логичный язык, почти на любой вопрос "почему" ответ - лишь цитата из спецификации.

Для механизма вызова виртуальных функций это не так.

Когда, например, создаётся объект класса C, который унаследован от класса B, а B унаследован от полиморфного класса A, то сначала вызывается конструктор A.

Объект в смысле динамического полиморфизма в этот момент представляет из себя класс A, как если бы конструировался объект не класса C, а класса A.

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

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

Именно поэтому механизм виртуального вызова, начиная с этого момента и до получения управления конструктором класса B, будет работать, как будто конструируется объект класса A, а не C.

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

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

Точно так же поступает конструктор класса C.

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

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

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

Таким образом, в процессе конструирования полиморфного объекта его динамический тип меняется в соответствии с тем, какой конструктор начал исполняться.

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

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

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

Я только что достаточно полно описал работу механизма динамического полиморфизма в C++, но не сослался ни на одну спецификацию.

Где здесь цитаты из спецификации?

С++ - не самый логичный язык

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

С поправкой на k получается O(nk^2).

Где вы там второй множитель k откопали?

for (size_t i = 0; i < values.size(); ++i) {
  for (size_t j = i; j < i + k && j < values.size(); ++j) {
    if (values[i] == values[j]) return true;
  }
}
return false;

Ну, или хотя бы O(n^2) с двумя вложенными циклами по всему массиву. Потом уже с мнимальными подсказками кандидат смог бы легко его исправить до O(nk), подкорректировав область внутреннего цикла.

Вы что, предлагаете взять каждое окно из k элементов и там за k^2 обойти все пары элементов? Вы как-то усложнили, смешав умное решение и наивное, получив более медленное. В наивном решении никаких окон не фигурирует вообще.

Алгоритм такой.

Да, это правильное решение за O(n). Да, это "алгоритмы". Но его на этом интервью не требуют. Это задача того же класса как и fizz-buzz, убедиться, что кандидат в состоянии написать простой цикл (или два).

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

Особенно логичен он при Argument-Dependent lookup, или integer promotion.

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

Ладно, давайте вернемся к сути спора. Вы тоже согласны, что алгоритмические собеседования яндекс проводить вправе - они ему нужны. Но считаете, что должно быть больше С++ собеседований?

Я не против C++ собеседований как таковых, но считаю, что они для больших компаний сильно дороже и сложнее, поэтому их и не вводят массово.
А без них жить в принципе можно: проверить, что кандидат способен базово писать на С++ можно и простыми leetcode задачками. Всякие тонкости вроде вызова виртуальных функций из конструктора всегда можно посмотреть в справке*. Тесты и ошибки компиляции исключают львиную долю ошибок связанных с незнанием этих тонкостей. И если кандидат способен думать, что решение алгоритмических задачек отлично показывает, то уж понять, как работает таблица виртуальных вызовов он точно сможет в первую неделю работы с кодовой базой, если там виртуальное наследование используется, в отличии от прошлых работ кандидата.

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

Где вы там второй множитель k откопали?

К данному решению, которое вы привели, ещё необходимо придти.

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

При этом ещё надо не ошибиться, что в конце необходимо дойти до самого конца массива, "сжимая"при этом окно.

Здесь требуется именно алгоритмический подход.

Вы что, предлагаете взять каждое окно из k элементов и там за k^2 обойти все пары элементов?

Естественно.

Задача бьётся на подзадачи.

На первом шаге имеется окно в k элементов, и требуется узнать, нет ли там дубликатов.

Эта подзадача выделяется в отдельный метод и решается за O(k^2), и этот метод вызывается n - k раз, отсюда O(nk^2).

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

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

Да, это правильное решение за O(n). Да, это "алгоритмы". Но его на этом интервью не требуют.

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

Это задача того же класса как и fizz-buzz

Для fizz-buzz не требуется алгоритмического мышления.

убедиться, что кандидат в состоянии написать простой цикл (или два).

На одном из публичных mock-интервью предлагали написать свою реализацию std::strlen, там как раз есть цикл.

Можно взять из того же семейства функций что-нибудь слегка посложнее.

Особенно логичен он при Argument-Dependent lookup, или integer promotion.

Какая-то общая логика даже там есть, например, изнутри — наружу.

Но механизм вызова виртуальных функций же — логичен?
Чувствуется там смысл, особенно, если подумать?

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

Да, я несколько раз написал, что если они нужны, то — нужны.

Но каждый раз замечал при этом, что они — не средство для проверки знаний и умений ещё и по C++.

Но считаете, что должно быть больше С++ собеседований?

Нет, я считаю, что собеседование по C++ должно быть по C++, а не по алгоритмам.

Если если ещё нужны и алгоритмы, то это должно быть отдельное собеседование или собеседования.

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

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

UB — недопустимо, потому что компилятор имеет право в этом случае генерировать неправильный код, и современные компиляторы этим усиленно пользуются.

А без них жить в принципе можно: проверить, что кандидат способен базово писать на С++ можно и простыми leetcode задачками.

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

Всякие тонкости вроде вызова виртуальных функций из конструктора всегда можно посмотреть в справке*.

Это — не вся правда.

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

Так и с механизмом виртуальных функций есть проблема: обычно, если кандидат не в курсе, ему и в голову не приходит, что здесь могут быть какие-то особенности.

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

Поэтому он даже не пытается ни в какую справку смотреть и что-то там искать по этому поводу.

Вот теперь — вся правда.

Тесты и ошибки компиляции исключают львиную долю ошибок связанных с незнанием этих тонкостей.

Нет, не исключают.

Просто будет вызываться не та функция, да и всё.
И это можно пропустить и не заметить.

Или, если UB привело к генерации неправильного кода, то код будет работать неправильно, вот и всё.

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

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

На собеседовании — точно не показывает.
Некогда на собеседовании думать.

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

Интеллект же применяется в минимальной степени.

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

То есть, натаскается по ходу дела на интенсивно используемые в проекте части C++?

То же самое тогда можно и про алгоритмическую часть сказать.

В целом, алгоритмическое собеседование по C++ очень плохо проверяет знания и умения, собственно, по самому C++.

Аргумент, что проводить собеседование по C++ — дорого, считаю ошибочным, потому что потом будет выходить дороже.

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

К данному решению, которое вы привели, ещё необходимо придти.

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

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

Задача бьётся на подзадачи.

На первом шаге имеется окно в k элементов, и требуется узнать, нет ли там дубликатов.

Как раз попытка ввести какое-то окно, это алгоритмический подход. У вас тут горе от ума.

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

Смысл в этой задаче такой же, как и у fizz-buzz. Проверить. что кандидат способен написать 2 вложенных цикла.

На одном из публичных mock-интервью предлагали написать свою реализацию std::strlen, там как раз есть цикл.

Можно взять из того же семейства функций что-нибудь слегка посложнее.

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

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

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

То же самое тогда можно и про алгоритмическую часть сказать

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

Ну, вы натягиваете сову на глобус.

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

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

Я на него уже ссылался.
То есть, не только я так думаю.

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

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

А иначе, как вы предлагаете, — даже не O(nk), а O(n^2).

Как раз попытка ввести какое-то окно, это алгоритмический подход. У вас тут горе от ума.

Нет, это результат попытки "понять чё хотят".
Результат перевода условия на "человеческий" язык.

Результат представления того, какие действия над массивом необходимо в целом провести.

Смысл в этой задаче такой же, как и у fizz-buzz. Проверить. что кандидат способен написать 2 вложенных цикла.

В это не верится, потому что задача — явно алгоритмическая и даже сформулирована математическим языком.

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

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

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

Не считают.

То-то качество постепенно сползает вниз.

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

Не защищают.

Тесты не могут покрыть все случаи, а ubsan и им подобные — это тоже, как и тесты, средство уровня runtime, то есть, на проявление UB надо наткнуться, предварительно создав для этого условия, а случай, когда создаются эти условия, может быть также не покрыт.

Тесты, в основном, помогают, когда необходимо проверить, что, в целом, всё работает. В целом, а не в частности.

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

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

Как это не понять?

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

Что значит "человеческий язык"? "Найти, если в массиве два одинаковых элемента, стоящие не дальше чем на k?" Это уже человеческий язык, или эту тривиальную задачу невозможно даже сформулировать на вашем "человеческом языке"?

Что значит "человеческий язык"? "Найти, если в массиве два одинаковых элемента, стоящие не дальше чем на k?"

Да, это уже человеческий язык, в отличие от "вернуть true, если в массиве существуют два конкретных индекса i и j, таких, что nums[i] == nums[j] и abs(i - j) <= k".

И при попытке это представить, появляется то самое "окно", реализующее собой условие abs(i - j) <= k, и это окно "дискретно движется по массиву", и на каждом шаге этого движения требуется проверить, нет ли в этом окне двух одинаковых элементов, и эта проверка реализует собой уже условие nums[i] == nums[j].

Этот "перевод на человеческий язык" как раз и есть то, что выражено в соседнем комментарии словами:

Надо напрячься даже не чтобы решить, а чтобы понять чё хотят.

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

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

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

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

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

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

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

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

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

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

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

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

Это так задумано - по 3 раза постить одно и то же?

Берет пример с яндекса )))

А шо там с зарплатами в яндекс после этой пытки?

Я выше уже приводил ссылки. В яндексе среднии зарплаты:

levels.fyi говорит, что мидл там получает в среднем 420 тысяч рублей в месяц: https://www.levels.fyi/companies/yandex/salaries/software-engineer/levels/g16. Хабр пишет про 200 тысяч в среднем для москвы: https://habr.com/ru/specials/748058/.

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

200к... 2000 долларов... для москвы... м-да...

Ну в целом понятно, всё так же тухло, как и после 2014.

Сказки про ОЧЕРЕДИ мне рассказывать не надо. Зачем писать в линкеде, убеждать пройти эти пытки, да ещё и часто через посторонних рекрутеров, если толпа за воротами?

И пока яндекс проводит "какие хочет собеседования", нонейм конторы предлагают столько же, а то и больше, после 1 короткого собеседования. Собственно, мой выбор )

Эм... Вы невнимательно прочитали мой коммент. 200к - это среднее по всем IT компаниям в москве. Яндекс же платит 420к.
А рекрутеры пишут - ну им же надо чем-то заниматься?

Спасибо, учту )

Sign up to leave a comment.