Куда ушло время во время интервью по кодированию «ноутбука»

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

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

Куда уходит время? В прошлый раз, когда я проходил через это, у меня в голове звучало что-то вроде этого:

(смотрит на бумагу) ага, ладно, что мне тут дают. Мне нужно взять несколько текстовых файлов из какой-нибудь дропбокса. Ладно, зайди в их гостевую сеть, поищи их файлы. Два входных файла, два выходных файла. Я должен взять ввод и превратить его в вывод, запустив некий алгоритм, который они объясняют на остальной части листа бумаги.

Файл ориентирован на строки, так что первая строка является числом, и это говорит о том, сколько строк данных будет следовать. Затем у них есть еще столько же строк, каждая с двумя числами, разделенными пробелом. Это не пришло с машины DOS, так что это, по крайней мере, не CRLF. Он появился не на Mac старой школы, так что это и не голый CR. Все заканчивается просто переводом строки, типичным для Unix.

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

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

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

Тогда давайте к этому. Хм, ну, у меня здесь нет ничего из моей личной библиотеки, так что, думаю, я могу кодировать все это по-старому. Кроме того, на чем они собираются это строить? Я понятия не имею, где они находятся с точки зрения компиляторов. Давайте предположим, что C++98 просто на всякий случай.

Хорошо, нужно получить файл, затем прочитать файл, так что…

 int main(int argc, char** argv) {   если (argc != 2) {     fprintf(stderr, "использование: %s <файл>\n", argv[0]);     выход(1);   } 

… и, конечно же, это означает, что нам нужен stdio.h для fprintf и stdlib.h для выхода прямо здесь, поэтому добавьте эти #includes вверху.

Продолжать идти. Открой вещь и кричи, если ее нет. Обычно у меня есть собственный LOG, но не здесь. В противном случае я обычно печатал что-то в stderr, давал ему сообщение и строку формата, а затем вставлял в него strerror(errno), но времени мало. perror противный, но он быстрее, так что к черту его, используйте его.

   ФАЙЛ* f = fopen(argv[1], "r");     если (!f) {     ошибка("открыть");     выход(1);   } 

А теперь нам нужен еще и errno.h. Иди #включи это.

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

И, черт возьми, fgets оставляет новую строку в конце, так что я должен связать это. Опять же, я думаю, я просто предположу, что здесь у меня есть нечто большее, чем пустая строка, и предположу, что я могу вычесть 1 из strlen, не углубляясь в сорняки. Именно поэтому у меня дома есть все эти причудливые штаны с чтением из файла в строку, которые были так кропотливо написаны!

   символ buf[1024];     fgets(buf, sizeof(buf), f);   buf[strlen(buf) - 1] = '\0'; 

Грязный. Так грязно. И теперь нам нужно число от этого. strtoul был бы правильным, тогда вся проверка ошибок, которую вы должны сделать, но это куча работы, и опять же, ни одна из моих домашних библиотек не спасет меня (которая уже сделала эту работу в этом). К черту это, atoi, и надеюсь, что ничего не выйдет, что не работает с этим.

   int input_lines = atoi (buf); 

[Проверка времени: мне потребовалось 17 минут только на то, чтобы *написать этот пост*, чтобы дойти до этого места. Я буду основываться на своих заметках и коде того дня несколько лет назад. Тик, тик, тик. ]

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

   fprintf(stderr, "XXX строк ввода: %d\n", input_lines); 

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

   карта <int, int> input_jobs; // ключ: время запуска, val: время выполнения     в то время как (fgets (buf, sizeof (buf), f)) {     если (strlen(buf) < 1) {       Продолжать;     }       buf[strlen(buf) - 1] = '\0';       char* sp = strchr(buf, ' ');       если (!сп) {       fprintf(stderr, "неверная строка (без пробела): %s\n", buf);       выход(1);     }       *сп = '\0';     char* len_str = sp + 1;       int start_at = atoi (buf);     int run_for = atoi(len_str);       input_jobs[start_at] = run_for;   }     fclose(f); 

ЗДЕСЬ ТАК МНОГО ПЛОХОСТИ. Нужно добавить что-то вверху: #include <map> и использовать std::map. Я действительно надеюсь, что они не дадут мне дубликат времени начала, иначе я раздавлю предыдущее. (Я думаю, они сказали что-то вроде «этого не произойдет», но почему вы вообще этому доверяете?)

Опять же, со слепым предположением, что у нас есть пригодные для использования данные для atoi… и с плохой строкой без пробела, ну, это тоже не должно происходить, но опять же, я не очень им доверяю. Я готов броситься на какую-нибудь глупость, но это приведет к ужасным вещам, когда он получит NULL обратно от strchr, а затем попытается разыменовать его позже, поэтому вместо того, чтобы писать еще одну ужасную дыру в указателе C 80-х, давайте просто умрем.

О да, я думаю, я должен убедиться, что они дали мне то, что, как они сказали мне, они дадут мне, так как я читаю EOF.

Вернитесь выше петли…

   целое фактическое = 0; 

…и в петле…

   ++фактический; 

… и после цикла:

   если (фактическое != input_lines) {     fprintf(stderr, "ожидаемое %d получило %d\n", input_lines, фактическое);     выход(1);   } 

Хорошо, так что теперь я буду знать, если это по крайней мере по какой-то причине.

[ Проверка времени: на написание этого поста ушло 27 минут. ]

Теперь я думаю, что мне нужно перебрать данные, которые я прочитал, и сделать с ними что-то полезное. О да, сначала прочитав его, а не «потоковый», я в лучшем случае обрек себя на ситуацию с памятью O (n), и, вероятно, это закончится еще хуже. Таким образом, эта временная вещь «считывать в карту», ​​вероятно, должна будет в какой-то момент уйти, и я вызову «добавить что-то, что я только что проанализировал» внутри цикла for. Радость.

В любом случае. Повторить. Но, ладно, C++98, такая итерация старой школы, ничего из этого «for const auto».

   map<int, int>::const_iterator II;     интервал_счетчик_работ = 0;   for (ii = input_jobs.begin(); ii != input_jobs.end(); ++ii) {     const int& start_time = ii->first;     const int& run_time = ii->second;     add_job (начало, время, время выполнения, job_count++);   } 

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

 static void add_job (int start_time_raw, int run_time, int job_number) {   fprintf(stderr, "XXX add_job %d | %d | %d\n\n",           start_time_raw, run_time, job_number);   // ХХХ напиши мне } 


Хорошо. Я пока остановлюсь на этом. Поймите, что то, что вы видите, является *окончательной формой* этого кода. Там куча вещей, которые произошли в промежутке. Например, посмотрите, как это называется «start_time_raw» в функции add_job? Это потому, что значение времени начала из файла оказалось «ЧЧММ». То есть 12:00 в файле было как «12:00». 13:45 было в файле как «1345».

Первоначально я проанализировал его как что-то в диапазоне 0-1439, потому что, ну, учитывая систему, которая позволяет вам планировать что-то в определенное время в течение дня с точностью до одной минуты, лично я бы использовал «количество минут с полуночи» в качестве базы. Они не были. Они использовали удобочитаемое время за вычетом обычного двоеточия, которое мы ставили посередине для удобочитаемости!

Как я узнал 1439? Я писал планировщики раньше, и обычный гражданский день, в котором нет переходов на летнее время, длится 1440 минут: 24 * 60. Из написания тех же планировщиков я также знаю, что неделя тех же дней без перехода на летнее время составляет 10080 минут, потому что это всего лишь 24 * 60 * 7, и вы часто сталкиваетесь с этим числом. Это впивается в твою голову. Или, по крайней мере, это засело *моей* голове. Что я могу сказать, я такой странный.

Итак, это start_time_raw, потому что оно не было разделено и преобразовано в значение, которое будет иметь смысл внутри массива. Первые фрагменты кода в конечном итоге add_job() сделали что-то ужасное, превратив ЧЧММ в «минуты с полуночи» в диапазоне 0-1439, например:

   int start_hour = start_time_raw / 100;   int start_minute = start_time_raw % 100;     int start_time = start_hour * 60 + start_minute; 

Ужасно, правда? Без проверки на вменяемость. Он просто модифицирует, делит, умножает, складывает и так далее.

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

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

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

Но эй, никакого давления.

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

Кроме того, я делал все это «argc, argv, fgets в buf, сжимал новую строку, делал это в цикле, нарезал на пробел и обрабатывал результаты» на C, вероятно, более сотни раз в моей жизни. к этому моменту. Я знаю все части. Я также знаю, какие детали могут пойти не так. Мне пришлось принять решение, что пропустить, а что оставить с точки зрения проверки работоспособности во имя экономии времени. Мне не нужно было тратить время на то, чтобы сделать эту работу. Тому, кто еще не прошел этот путь, будет не так легко.

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

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

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

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

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

Это. Именно туда идет время.

Упреждающая боковая панель: «ей следовало использовать Python». Просто уходи. Вы *так* упускаете суть.

Leave a Comment

Ваш адрес email не будет опубликован.