Собеседование Middle C++
Vložit
- čas přidán 21. 07. 2023
- Всем привет!
Провели тренировочное собеседование с Валентином на позицию Middle C++ Developer.
Приятного просмотра!
Не забудьте поддержать видео :)
Twitch: / ambushedraccoontv
Telegram: t.me/AmbushedRaccoon
Donate: www.donationalerts.com/r/ambu...
Спасибо, как всегда, круто 👍🏻
не знал что оксимирон проводит собесы
Ну и на каких реальных проектах решаются такие типовые задачи?)Решаются задачи вроде разбор архитектуры,нахождение эффективного решения,написание опредленных подсистем,тут намного больше нужно аналитическое мышление чем знание синтакиса С++.Если возникают проблемы с синтксисом то это гуглиться за пару минут.Весь этот литкодный подход это на поиск кодера,человека который бездумного просто будет выполнять задачи.В настоящее время переизбычтка игфрмации запоминание типовых алгоритмов-вздор😁Намного больше смысла для позиции от Middle давать задачи на построение архитектуры и эффективного решения,даже на псевдокоде
Кинь пожалуйста тогда ссылку на какой-то собес, который тебе понравился, по С++
Наконец-то что-то новое по cpp
Во время обсуждения реаллокации вектора ждал что упомянут инвалидацию итераторов, указателей и ссылок, но не услышал. Но момент не всегда очевидный и новички периодически на него попадаются.
Ага, а ещё конструкторы перемещения/ копирования могут бросать исключения. И кстати выбор между ними, и оптимизация реаллокции простых типов.
можно ссылку на документацию?
По второй задаче: изначально можно было идти по аналогии с std::string::find. Вернуть аналог npos.
Чувак удивил, что смог isSame реализовать, но не выдал базу про set :)
Может isSame он и смог благодаря документации)
хз, очень странно что он не знает что такое специализация, потому что начал в оригинальном шаблоне писать
но мб прост волновался, каждый мнит себя Страуструпом видя собес со стороны)
@@allex-all Да, очень похоже, что он код из документации переписал
27:34 - совсем не обязательно переходить к ssize_t, теряя половину возможных значений, хотя требуется всего одно.
Тем более, что в стандартах C/C++ этот тип не определён, хотя можно найти решение даже в этом случае, например, std::make_signed_t.
Вполне достаточно пожертвовать всего одним значением, а именно -- максимальным, и ограничений это не внесёт никаких в силу наличия NULL-указателя.
Для этого можно использовать SIZE_MAX (требуются header'ы cstdint и climits) или std::numeric_limits::max() (требуется header limits).
Есть небольшое ощущение, что у интервьюера за последние полгода-год уровень подрос.
Создавать в коде спящие баги не очень хорошо =) Хоть я и не могу представить ситуацию когда потребуется полностью заполненный вектор...
У меня был этап когда я писал максимально ужатый код. Пытаясь выиграть по максимум памяти и быстродействия, ни к чему хорошему это не приводит обычно. Сложность возрастает, расширяемость падает. Да и не ты один над кодом трудишься...
А в данном случае я бы возвращал булевский результат. А значение отправлял по ссылку. Ну или дополнительно где-нибудь добавил флаг ошибки. Всё зависит от конечного использования.
@@bergest4348 Возвращать не значение, а bool'вский результат, а само значение -- по ссылке, может быть неудобно.
Это не похоже на "спящий bug", тем более, что SIZE_MAX практически наверняка недостижимо, ибо как минимум один адрес (NULL) исключается.
Если вы посмотрите на cppreference описание strtoul в части возвращаемого значения, то увидите, что там подход -- аналогичный.
В стандартной библиотеке C++ тоже создают спящие bug'и?
@@billjohnes9380 В любом случае это особенность которую нужно помнить. По поводу логики - а смысл тогда возвращать ошибку если мы не делаем обработку этих ошибок. Единственная проблема - 2 доп переменных, которые в случае с ограниченной памятью нам не нужны. Ну моё мнение - реализация зависит от конкретной задачи.
@@bergest4348 Эта "особенность" широко распространена, включая случаи возврата беззнаковых типов, и даже встречается в стандартной библиотеке.
В программировании вообще много особенностей, про которые следует помнить, иначе -- чревато.
Может быть так, что обработка ошибок отдаётся выше в вызывающие функции, и в случае возврата SIZE_MAX при ошибке нет необходимости в переменной.
И даже если не отдавать ошибки на обработку выше, то в вашем случае невозможно завести const'антную переменную, которая примет значение.
Однако, моё изначальное замечание касалось не разумности применения в данном случае техники возврата специального значения как индикатора ошибки, а всё-таки использования данной техники разумным способом, а не тем, который был озвучен во время собеседования.
@@billjohnes9380 с этим я полностью согласен =)
Ну что то мало.
Хотелось увидеть лямбды, особенности их работы, применение в стандартных алгоритмах. Ну и потихоньку подтягивать фичи из новых стандартов (ranges, views).
Дык а что лямбды разбирать. Генерируется класс функтор с перегруженным оператором. Не вижу ничего сильно интересного в них
@@valentynmudryk2869 а зря, в них много интересного, например как использовать лямбды внутри списковой инициализации структур, что из себя представляет лямбда с auto аргументом (в функции до недавних времен auto в аргументы было нельзя писать, а в лямбды можно), про friend'овость лямбд объявленных в методах структуры (есть ли вообще возможность обращаться к private), про проблемы с оптимизацией в лямбдах, что делает mutable по отношению к лямбде и тп. :)
nice
Спасибо, понял, что стоит подучить stl, а то как то нервно стало на шаблонах.
Да и winapi посмотреть.
Ps но все таки есть мысль, что для миддла важнее паттерны проектирования, алгоритмы и все что более существенно влияет на жизнь и стоимость проекта.
Все таки шаблоны , stl и низкий уровень нужен тем, кто пишет библиотеки, а не десктоп.
Важнее быстро написать надежный код, а не написать быстрый код.
Так можно вообще писать код на ноде или питоне. Зачем вам плюсы тогда?
Быстро написать надёжный и ПОНЯТНЫЙ код ))) но я ненастоящий сварщик, хотя и пытаюсь стать настоящим
@@jnarical так быстро и понятно это не в плюсы . Тут ни того ни другого.
Вот именно, в первую очередь с чем ты сталкиваешься это с архитектурой ПО, а уже потом все остальное, если алгоритмы ты можешь нагуглить и выучить по ходу применения, то с архитектурой не все так однозначно
@@whoknows4728 нагуглить и вкурить паттерны
👍
Разве решение первой задачи не является ошибочным? Оно не учитывает числа, большие чем number. Так для number = 3. оно проигнорирует 33, 333 и т. д.
Я недавно начал изучать c++, попробовал решить эту задачу, у меня получилось так:
int getMax(const int *arr, int size, int number)
{
int maxFirst = 0;
int maxSecond = 0;
for (int i = 0; i < size; ++i)
{
if (arr[i] == number)
{
++maxFirst;
if (maxSecond < maxFirst)
{
maxSecond = maxFirst;
}
continue;
}
maxFirst = 0;
}
return maxSecond;
}
Там условие задачи звучит как "найдите количество цифр в самой длинной последовательности, состоящей из числа number." Этот код явно делает не это) И я бы Вам порекомендовал использовать std контейнеры вместо встроенных массивов
@@user60336 С тем, что лучше использовать встроенные контейнеры вместо массивов я с вами согласен, но с чего вы решили, что данный код не удовлетворяет условию задачи?
@@crazyboom8909 Как минимум потому, что он для последовательности чисел, приведённых в видео, для которых он должен возвращать ответ 4, возвращает 1)
@@crazyboom8909 Если я правильно понял условия задачи, как-то так должен выглядеть ответ.
int find_range_n(const std::vector& vec, int number)
{
int max{};
for (auto n : vec)
{
int temp_max{};
while (n > 0)
{
if (n % 10 == number)
{
temp_max++;
}
n /= 10;
}
if (temp_max > max)
{
max = temp_max;
}
}
return max;
}
Какие навыки или опыт проверяет первая задача?
умение соображать
@@arthurlouiskarl решать задачки и писать код это совершенно разные задачи. Он собесит на должность в команду спортивного программирования?
@@RedBallOfLove С этим никто не спорит. Вот только вызубрить документацию, фреймворки и паттерны может любой, что там проверять-то? а такие задачи решит не любой, даже с подготовкой. Только тут виден ум и находчивость кандидата
@@arthurlouiskarl Только в 0.01% случаев, а может быть и меньше, вам приходится сталкиваться с сортировками. Остальное же время приходится прикручивать разные фреймворки, настраивать, ловить сотни различных багов и обходить их, собирать всё это вместе, пытаясь заставить этого монстра работать. Практически любое узкое место можно выловить на этапе оптимизации, а вот написать код, который можно будет читать, поддерживать и расширять - реальная проблема.
@@RedBallOfLove я и не спорю с этим. На подробное обсуждение построения архитектуры нужно много времени и это делается на отдельном интервью (так и называется обычно, дизайн приложений), на алго-интервью важно понять, насколько человек умеет думать. Если вы никогда не сталкивались с кем-то, кто хорошо говорит, имеет много лет "опыта", но не может понять логику простой сортировки или бинарного поиска - то, поверьте, такие бывают и их много.
Это такой тест на мидла? )))))))))
Смотрю такие видео и думаю: а они вообще программировать умеют?😅😂😂😂😂
Не понятно какой документацией он пользовался ? Очень удобная штука, напишите название пожалуйста.
Zeal
Zeal
Zeal
Первая задача вроде как решена не правильно. find находит первый элемент в контейнере - получается эта функция для вектора vec = {5, 1, 1, 4, 1, 1, 1, 1, 1} и number = 1 вернет 3 (зацепив 5-ку), хотя правильный ответ 5. Я так понимаю он хотел написать что-то типа этого:
size_t max = 0;
auto first_match = std::find(vec.begin(), vec.end(), number);
while(first_match != vec.end()) {
auto last_match = std::find_if(first_match, vec.end(), [number](const int elem){return elem != number;});
max = std::max(static_cast(std::distance(first_match, last_match)), max);
first_match = std::find(last_match, vec.end(), number);
}
return max;
Хотя он, вроде как, не эффективнее наивного решения (Оба за O(N)), просто выглядит компактнее и более читаемо
Для Джуна здесь много незнакомого, и многое непонятно))
где таких лажовых мидлов брать?
Ответ про специальные команды процессора для работы с исключениями убил. 😂 И чел явно путает try и __try.
Плохая привычка не проверять своё решение, разве так сложно собрать проект и проверить правильно ли работает ваша программа? Судя по софту, что сегодня выпускают, на работе они тоже программы даже не тестируют и не запускают... надеюсь когда нибудь эта привычка уйдет у разработчиков
Далеко не на каждом собеседовании у вас будет возможность собрать и запустить решение.
Тем не менее критику я учел.
int find_range_n(const std::vector& vec, int number)
{
char cnum = '0' + number;
int maxn = 0;
for (auto el : vec) {
string strn = to_string(el);
int len = ranges::count(strn, cnum);
if (len == strn.size() && maxn < len) {
maxn = len;
}
}
return maxn;
}
Что в видео, что в комментах, реализация этой функции вообще не имеет отношения к поставленной задаче.
Вот правильное решение, хотя и не оптимальное.
Как по мне инкрементить значения при переборе не имеет смысла(1я задача). Достаточно использовать разницу указателей. Поскольку вектор это тот же массив в юбке.
Привет. Не мог ты показать пример? Опыт лишним не будет :)
Я cделал так (по сути схоже с его реализацией):
int find_range_n(const std::vector& vec, int number){
int count{0}, maxCount{0};
for (auto a:vec) {
if (a == number) {
count++;
if (maxCount < count) {
maxCount = count;
}
}
else {
count = 0;
}
}
return maxCount;
}
Громоздко.
@@isljack3117
int find_range_n(const std::vector& vec, int number){
const int* first = nullptr;
long int res = 0;
for(auto& i : vec) {
if(number == i) {
if(!first)
first = &i;
} else {
if(first) {
res = std::max(res, &i - first);
first = nullptr;
}
}
}
if(first) {
return std::max(res, (&vec.back() - first) + 1);
}
return res;
}
@@bergest4348 Твое решение хуже читается и менее эффективно. У тебя на каждую итерацию делается больше условных проверок, которые сложнее чем просто инкрементировать значение. Так же твое решение хуже масштабируется, если нам в будущем понадобится реализовать такой же алгоритм для другого типа контейнера, например, для списка, твое решение не будет работать.
Что-то унылый какой-то мидл, я так пару недель в VisualStudio посижу и за синьора сойду 😀
КьюТЭ. Всё -уволен. Не прошел 😂😂😅
Ваще нифига не понял чо за дичь в задачах была и почему типеид не катит
Потому что "типеид" не будет работать при выключенном RTTI. И вопрос был именно про шаблоны а не RTTI.
У нас в конторе все говорят "кутИ", хоть кол на голове чеши)
По первой задаче: Кто нибудь, объясните мне, дураку, почему этот код вообще должен работать?
if (n = number) - оно же никогда не выполнится. N последовательно перебирается элементами массива, number = 3.
Может, если надо найти самую длительную последовательность из 3, надо так:
unsigned int max_arr = 0;
for (auto n: arr) {
if (n % number != 0) continue;
if ((n / number) > max_arr) max_arr = n;
}
Тогда на выходе, да, получим самый длинный элемент, состоящий из последовательности number
Чел сидит и гуглит параллельно
Не совсем так.
1:00:38 - тут про это говорю.
Хех, я примерно так и понял, слишком уж хорошо отвечает и слишком много всяких штук помнит.
Без того чтобы помнить, документация не поможет. Это инструмент поддержки
@@valentynmudryk2869 Конечно нужно с этим работать, чтобы в этом инструменте был смысл, но он действительно даёт буст на собесах. Например я не уверен, что вспомню сейчас как сфинае писать, т.к на работе не пишу его. Но что это знаю, и с этой штукой точно отвечу на вопрос, а без неё - не уверен. Тут вопрос подготовки, на собесах очень часто спрашивают то, что как правило не используется на работе. Те же шаблоны, редко на практике применяются.
@@vladimirchizh8853 SFINAE разное бывает) Что-то можно без подготовки написать, а что-то уже затруднительно
слабоваты вопросы для позиции мидла уж мне кажется
Мда уж
нынче блогеры в прогеры решили податься.....мда. Потом удивляемся почему программы такие тормознутые получаются...
middle переменную называется a и b...завтра сеньором будет, начнет называть их _a и _b....
КККланг а не СИланг
не душни
Какой он унылый, печатает со скоростью секретарши, мидл школьник
Как по мне на typescript-е люди посложней решают задачи)) перебирать массивчики это такое себе)) спроси лучше что такое тред пул и как работают форки например)) как пробросить исключение через поток и т.д
Так он сказал же, что исключениями не пользуются, а только ловят.
Зачем тогда это спрашивать? Много где считают, что исключениями пользоваться не надо. Это убивает смысл С++.