Как стать автором
Обновить

Комментарии 131

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

Заметил, что только в ИТ сфере есть такие дебильные собеседования.

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

Забавно, что иногда такие задачи в ИТ встречаются: например, как на лету прочитать дамп ffmpeg vstats при условии, что он пишется исключительно в файл (в стандартный выхлоп не умеет).


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


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

Ну так предлагайте реальные задачи, а не «не используйте операцию сложения». Нет в природе ситуаций, когда нельзя использовать сложение.

Само-собой, бывает, что нужно провести операцию в лифте, отрезать ногу в поле, замотать трубу тряпкой в эпоксидке, отбиться от гопников перед подъездом клиента. Но никто не нападает на кандидатов перед собеседованием и не запирает в лифте с больным. Когда-то давно были только люки от гугла, теперь вот пошло в массы.
Конечно же в природе есть ситуации, когда нельзя использовать сложение.
Например, когда ваша задача реализовать сложение в архитектуре процессора который вы разрабатываете.
На питоне? :)
В природе.
При разработке архитектуры, наверное будет невыгодно реализовывать сложение через логарифмы или вычитание. Иначе это будет очень очень медленный и плохой процессор.
На объяснение «реальной задачи» может уйти 10 минут. И если я уже знаю, что «реальная задача» сводится к «найти наибольший элемент в массиве без использования оператора сравнения» — то я сэкономлю 10 минут и дам сразу задачу в сжатом виде. Потому что на собесе время ограничено. И если кандидат успеет быстро решить задачу — то поясню, откуда она такая взялась и как она относится к нашей деятельности. Но только если времени хватит.
Если вы не можете придумать реальную задачу, которую можно объяснить быстрее чем за 10 минут, это не проблема задач.
Если ваша реальная задача сводится к тому, чтобы заниматься таким вот извращением, возможно вам стоит отойти на шаг подальше, и понять где именно вы свернули не туда, а не собеседования устраивать.
Если вы не можете придумать реальную задачу

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

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

Кажется, вы забываете о том, что не всё программирование делается по шаблону. И иногда приходится обрабатывать терабайты неструктурированных данных для которых оператор сравнения не определён (точки на графе, например).
На объяснение «реальной задачи» может уйти 10 минут. И если я уже знаю, что «реальная задача» сводится к «найти наибольший элемент в массиве без использования оператора сравнения» — то я сэкономлю 10 минут и дам сразу задачу в сжатом виде.
Способность декомпозировать задачу до уровня простых алгоритмов так явно не проверить. Джунов имеет смысл так проверять, но только их, кмк.
Способность декомпозировать задачу до уровня простых алгоритмов так явно не проверить. Джунов имеет смысл так проверять, но только их, кмк.

Я согласен, что декомпозицию так не проверить. Но когда я провожу собеседование — я сначала проверяю, что человек тянет хотя бы на джуна, а потом уже даю мидловские/сениорские задачи.
Если собеседовать «по матрице», то подход верен. А если на конкретную позицию, требующую левел, то я бы сразу переходил к вопросам повыше (слегка странно на сеньора слышать вопросы а-ля «как создать класс исключения и потом использовать его в коде», причем кейс — реальный). Максимум — это вопросы, тянущие на полгрейда ниже — все-таки резюме интервьюер перед собесом видит. Так и время сэкономится, и качество отбора повыше будет. Имхо.
Не всё то правда, что в резюме. Не каждый претендент на сеньора — джун. А вообще проще надо всем быть. А то одни изображают из себя супер профессионалов и считают, что алгоритмические задачи недостойны того, чтобы их решать, я ведь не джун какой-то. А потом выясняется что решить то эту «задачку» не так-то просто. А другие придумавают такие «задачки», которые чтобы решить надо быть Вассерманом в программировании, а потом выясняется, что на работе надо домашний страницы делать. В общем баланс должен быть везде и гармония :)
Конечно, в резюме много чего можно встретить. Но я немного не о том.
Идея в том, чтобы на собесе на сеньора сразу спросить вопросы, по ответам на которые человек либо явно сеньор, либо скорее мидл, либо точно джун. Эдакие маячки. Вряд ли по ответу на вопрос «что такое декоратор» можно такое предполагать (ну разве что кандидат, увлекшись, начнет декоратор сразу в байткоде набрасывать :) ).

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

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

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

Ну вообще-то, такая программа как tail именно это и делает, читает в свой stdout всё что валится в файл.

А еще есть именованные каналы

в стандартный выхлоп не умеет

Он не не умеет, а сделано это целенаправленно.
ffmpeg в stdout может выводить видео или аудио поток, и тогда этот поток можно принимать другой программой обработки.

Именно по этому, ffmpeg делает текстовый вывод в stderr. Но ни кто не мешает stderr перенаправить в stdout средствами операционной системы:
fmpeg -i input.mp3 2>&1

Почитайте документацию, посмотрите код. Vstats пишется исключительно в файл.

ИМХО, самое ужасное в этих вопросах — зачастую очень плохо задаются условия задачи и ограничения.
В статье это тоже есть. Язык — только в тегах, можно ли использовать библиотеки, которые используют "+" под капотом — не сказано.

Иногда из-за этого получается забавный эффект — «правильно» задачку могут решить только те, кто знают одни вещи, и не знают другие. Потому что если знаешь слишком много — отвергнешь «правильное» решение.
Что ещё плохо — непонятно, что именно от тебя хотят. Проверить знание математики? Алгоритмов? Стандартной библиотеки? Встроенных возможностей языка? Или просто ищут повод, чтобы отказать чем-то не понравившемуся кандидату.
Обычно если прямо спросить — ответят «мы хотим увидеть, как вы мыслите». Но объяснить, что же именно в этом мышлении они анализируют, обычно не могут.
То есть у них самих нет готового алгоритма типа «если кандидат использовал библиотеку — то он относится к группе людей 1, если кандидат сформировал плюс из символов — то он относится к группе людей 2».

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

Так что по факту это просто ИБД — имитация бурной деятельности. С тем же успехом человека можно посадить проходить тест Люшера.
Так что по факту это просто ИБД

Кстати да. Я вполне могу представить ситуацию, когда кандидат уже подходит, но по процессам компании собеседование всё равно нужно провести. Спрашивать элементарщину тоже вариант, но придумывать свои задачки-головоломки тупо интереснее, а слышать в 20 раз о том, как работает хеш-таблица — тупо скучнее.
А на практике из 20 раз услышать один-два вменяемых ответа — вполне норма. А уж как работает хеш джойн — и того куда реже.
Если кандидат подходит, а собес нужно для галочки, то проблема в процессах, ведь, пока человека ищут/собеседуют, компания теряет время, а время=деньги. В конце-концов, просто сократить время собеса до 15 минут и поговорить с человеком о задачах, которые ему действительно придется решать на проекте — так и интересно, и с пользой. А все эти задачи вроде «сосчитать до бесконечности» или «сколько жирафов поместится в лондонский автобус» — это либо пустая трата времени, либо садизм по отношению к кандидату (и себе, если делается без удовольствия).

З.Ы: особенно ярко проявляется в конторах, как из этого примера.

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

Так код и нельзя показывать, а то «придут люди, умеющие убеждать» — злой дядя Начальник-Безопасности и неумолимая тетя NDA.

Рассказать о стэке, с которым придется работать, и задачах можно и без раскрытия всех карт. «Есть зоопарк Postgres+MySQL+Firebird» или «Ядро — легаси, писанное индусами на Коболе», ну или «система писалась в режиме стартапа, поэтому есть много неоднозначных мест, которые надо сделать однозначными. Например, стабилизировать модуль отчетов, настроить автодеплой или починить бота-заказчика картошки оптом». И без приукрашиваний, и конфиденциальность соблюдена. :)

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

Если 5 разных способов на самом деле разные, то ок.

Если 5 способов это почти копии одного (5 вычислений через минусы со сменой знака в конце, например), то не ок.

Ну и промежуточные вариации.

«Нам угрожает начинённый атомными бомбами инопланетный космический корабль. У нас есть транспортир» — Нил Стивенсон, «Анафем»

Правильный ответ на вопрос "как?" не может быть дан при неимении ответа на вопрос "зачем?".

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

"Задача - удалить гланды. Условие - через рот нельзя."

Ответ выше был: «трахеотомия с помощью пвх-трубы и зажигалки».
Сложить два целых числа (от 1 до 99) без использования оператора 'плюс'

А самый тупой вариант — таблица с вариантами для каждого случая? Типа if (a == 1) { if (b == 1) return 2;… }…
Почему тупой? Так и программируют индусы, между прочим. И не стесняются.
Массивом проще
Но это уже будет не самый тупой вариант :)

Правильный ответ - после первого вопроса встать и уйти. Не дай Б-г еще возьмут на саппорт уже написанного в этом духе.

НЛО прилетело и опубликовало эту надпись здесь
Имхо, есть ещё 4 решения намного проще:

1) a+b === 2a-x, где x = a-b
2) a+b = c === c-a == b… a, b in [0, 99] => c < 200….
a = 15
b = 24
for bv in range(200, 0, -1):
    if bv-a == b: 
        break
print(bv)

3. табличное сложение — предварительно в коде размещаем таблицу 99x99 — где каждый элемент является сложением индеска.
4. сложение генератором — if и switch наше всё…

но это не так весело…
Это самые разумные общеалгоритмические подходы, но автору захотелось поупражняться в хаканьи Python internals. Кама-сутра по вызову python opcode add через нетрадиционные места.
А как можно было бы развернуться на C++ с использованием template metaprogramming!
Ну, классическому компилируемому в нативный бинарный код языку на самом деле труднее конкурировать с обфускацией внутренних вызовов чем скрипту с развитой рефлексией и built-in eval. Вот JavaScript-хацкеры тут повоюют.
Возможность прямого доступа в память и выполнения ассемблерных вставок вряд ли побивается любой самой развитой рефлексией.
Ну, рефлексией, наверно, не перебивается. Но против eval-а приемов нет, потому что с исходным кодом как вычисляемым ресурсом в рантайме можно нагенерить вообще все что угодно. Темплейты хотя и полны по Тьюрингу, но выразительно гораздо менее гибки чем родной исходный текст.

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

Можно отсортировать аргументы (if (a > b) swap(a, b);) и оптимизировать таблицу.

«Сложить два целых числа (от 1 до 99) без использования оператора 'плюс'. Дайте пять разных ответов»

plus1 = 100 — (100 — a — b);
100 не нужно. Просто умножение на -1
А показалось… ладно, неважно, вот мои 3 (недо)решения:

1) 100 — (100 — a — b)
2) (0 — a — b) * (-1)
3) Используем что a**2 — b**2 = (a — b)(a + b), соответственно (a**2 — b**2)/(a — b), a — b != 0
А зачем во втором случае ноль? Почему не просто (-a-b)*(-1)?
недочет, действительно)
Спасибо за поправку)

Потому что без нуля будет уже следующий способ решения, о нём уже писали :))

Первый вариант сразу пришел в голову, только не 100 использовал а 198 (потому что числа от 1 до 99, т.е оба могут быть 99) 8-)

НЛО прилетело и опубликовало эту надпись здесь
А можно было на первый вопрос сразу ответ написать? Ну, чтобы те, кто с питоном не знаком, не чувствовали себя дураками, пытаясь найти ошибку в
спойлер
использовании синтаксиса

(Или я единственный, кто упорно думал над этим случаем?:))

Там нету ошибок. PEP8 — это набор рекомендаций, не более. Его нарушение является ошибкой настолько же, насколько является ошибкой


for(...)
{
   do_stuff()
}

вместо


for(...) {
   do_stuff()
}
НЛО прилетело и опубликовало эту надпись здесь

Ну на листе бумаги же заставляют

Не знаю насколько это распространённая вещь, но экзамен в техническом вузе нас так заставляли сдавать. На С.
if a<>b then
  writeln((a*a-b*b) div (a-b))
else
  writeln(a*2);
Ух, с решением на основе разности квадратов опередили, пардон.
Тогда так:
writeln(a*2 - (a-b));
Но это же тоже самое что и первое решение в посте.
Так можно до бесконечности продолжать
print(a*3 - (a*2-b))
Формально — нет, идейно — да.
Заодно плюс повод подискутировать с интервьюером и оценить глубину его шибанутости :)

Ну так неинтересно. Вот если бы у вас не было ADD/SUB в доступном подмножестве ассемблера...

  1. Цикл с INC a, DEC b и выходом когда b = 0
  2. Полный сумматор (побитовый)
  3. Через сумму логарифмов (углов синусов, квадратов или любым другим математическим фокусом)
  4. Через память (массив 100*100 с ответами)
  5. ???
mov, lea

Есть такие задачки, до сих пор помню code challenge 15-летней давности, который меня выбил на неделю

язык: asm

набор инструкций: I 386**

цель: написать DOS программу (.com), которая принимает на стандартный вход 1 байт (число 0-255) и выводит в стандартный вывод N знаков $, где N - число на входе, после чего завершается с кодом 0

критерий оценивания: побеждает программа минимального размера

** ну, и маленький нюанс: нельзя использовать команды условного перехода (jz, je, jne и т.п.), нельзя использовать арифметику (add, sub, inc, dec, mul, div), в том числе адресную арифметику (lea, dword ptr [eax + 4] и т.п.)

Победила программа размером (кажется) 19 байт

Сдается мне, там был разрешен loop. Тогда читаешь в CX, выводишь бакс через int21, loop, int20. Иначе никак в 19 байт не уложиться.

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

Подтверждаю — это — кратчайший путь. Когда писал io.tpu, crt.tpu и dos.tpu именно так и поступал (ну, любил я Паскаль, а "дистрибутив" достался без turbo.tpl)

сразу видна позиция программиста в крупной компании (может даже корпорации). Сверху сказали не использовать плюс в рассчетах — значит не использовать плюс в рассчетах.

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

Сверху сказали отказаться от С++, то есть буквально такой приказ:

— Перестаньте использовать плюсы!

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

Дело было так, пришел новый chief architect в компанию и сказал «У нас на прошлой работе плюсов небыло». Ну все и завертелось.

Вот вы смеётесь, а у нас был китаец, который так и писал. Как увидел код, так вздрогнул.

Лучше сделать раз 10 и взять среднее, для большей стабильности.
Прятание плюса в строки — скучно. Фокусы с логарифмами, синусами и пр — забавно, но за преобразование целых чисел в float и обратно нужно наказывать.

Не соглашусь. Есть ситуации и их много, когда нужно float преобразовать в int32 к примеру. Записать в EEPROM результат с точностью до сотых -- float * 100 и отбрасываем дробную часть. Не вижу никаких проблем. Может поделитесь опытом почему нельзя?

Во первых погрешности 2 преобразований. Во вторых - обе операции достаточно сложные.

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

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

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


а) так повелось с тех древних времен, когда пароли сохранялись в таблицу
б) пароли до сих пор сохраняются в таблицу

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

Длина СМС?

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

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

Аккуратнее в выражениях, времена нынче такие, что Вас легко могут привлечь по статье "Разжигание профессиональной розни к социальной группе 'Разработчики-родственники чиновников госструктур'".
Причём по этапу пойдёте и Вы, как комментатор, и я, как parent-комментатор, и автор поста.
Да и вообще все, кто открыл эту страницу.

НЛО прилетело и опубликовало эту надпись здесь
Я с таким проектом в далекие джуновские годы имел дело. Правда, пинать было некого — автор сего творения ушел оттуда еще до моего прихода.

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

Боится SQL injection :D с учетом "не пихайте пробелы в пароль"

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

Это что ж за номер был, что не влазил в 15 символов?

Клиент был из Питербурга и в поле номера дома он написал что-то вроде «Дом №7, литера А»

Про 120 не знаю, знаю про 72 из своего дивного доисторического опыта в php :) Blowfish и bcrypt игнорируют остальные символы. Может что-то подобное и про 120 есть.

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

Универсальное правило для подобных головоломок и собеседований:

В любой непонятной ситуации говори: «lookup-таблица»! (И начинай думать, как её применить).

Сделать список из чисел от 1 до 189 и итерироваться по нему b раз, начиная с позиции а :)
(типа сложение по аксиомам Пеано)

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


Заголовок спойлера
def add0(a, b):
    return a - (-b)

# =======================================

def add1(a, b):
    return a.__add__(b) # a.__radd__(b)

# =======================================

def add2(a, b):
    def inc(a):
        return -(a ^ (-1))

    bin_a, bin_b = bin(a)[:1:-1], bin(b)[:1:-1]
    res_len = inc(max(len(bin_a), len(bin_b)))
    res = '0' * res_len
    bin_a = f'{bin_a}{"0" * (res_len - len(bin_a))}'
    bin_b = f'{bin_b}{"0" * (res_len - len(bin_b))}'
    zz, zos, oo = ('0', '0'), [('1', '0'), ('0', '1')], ('1', '1')

    for (i, (ba, bb)) in enumerate(zip(bin_a, bin_b)):
        if (ba, bb) == zz:
            continue
        elif (ba, bb) in zos:
            if res[i] == '0': 
                res = f'{res[:i]}1{res[inc(i):]}'
            else:
                res = f'{res[:i]}01{res[inc(inc(i)):]}'
        elif (ba, bb) == oo:
            res = f'{res[:inc(i)]}1{res[inc(inc(i)):]}'

    res = res[::-1]
    return int(res, 2)

# =======================================

def add3(a, b):
    if a == b:
        return 2 * a

    m = max(a, b)
    for z in range(m ** 2):
        if z - a - b == 0:
            return z

# =======================================

def add4(a, b):
    if a == b:
        return a * 2

    import math
    a, b = min(a, b), max(a, b)
    c2 = round((b / math.cos(math.atan(a/b)))**2)
    a2b2 = c2 - 2 * a**2
    return a2b2 // (b - a)

# =======================================

def add5(a, b):
    # Свернул для комментария, для ответа развернуть в
    # {(1, 1): 2, (1, 2): 3, (1, 3): 4, (1, 4): 5, (1, 5): 6, ...}
    all_results = {(a, b): a + b for a in range(1, 100) for b in range(1, 100)}
    return all_results[(a, b)]

def test(f):
    test_flag = True
    for a in range(1, 100):
        for b in range(1, 100):
            if f(a, b) != a + b:
                test_flag = False
                print('error in ', a, b, f.__qualname__)
    return test_flag

for f in [add0, add1, add2, add3, add4]:
    if test(f):
       print(f.__qualname__, 'is good') 
Круто!
Кстати, в первое мгновение я понял заголовок поста как «Как проходить собеседование если у вас нет достоинств (== положительных сторон)».
выбираем из двух чисел большее
умножаем на два
вычитаем из большего меньшее
вычитаем из произведения разность

пример:
21+37=58

37*2 = 74
37 -21 = 16
74 -16 =58
Был у меня такой вариант, но я его даже не стал писать. Т.к. он сводится к первому решению.
Допустим, a > b. Тогда a * 2 = a + a
сокращаем:
a + a — (a — b) => a — (-b)
Легко заметить, что это решение работает и без выбора большего из двух слагаемых.
2а-(a-b) = a+b независимо от того, что больше — a или b.

@sukhe Круто было бы на GitHub сделать репозиторий и в нем папочки для разных языков. И принимать туда pr)

from time import sleep, time

left, right = map(int, (input(), input()))

now = time()
sleep(left)
sleep(right)
new = time()

print(int(new - now))
Второй вариант, думаю, очевиден

Зря вы так все человечество под математиков подписали )

Подумал про три варианта, один - через побитовые операции автор описал, спасибо, + а ведь ещё есть

Модулярная арифметика, вангую, что можно через деление.

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

можно перевести в двоичный вид и по разрядам логическими операциями просуммировать как в АЛУ

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

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

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

2. Lookup-таблица с вычисленными заранее результатами.

3. Сокрытие вызова. Здесь мы на самом деле вызываем всё тот же add что и при использовании оператора "плюс", но делаем это без использования оператора. Решений также несколько, все они сильно зависят от конкретного ЯП.

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

5. Использование внешнего источника. Реализация нужной операции берётся из среды выполнения — окружения или библиотек.

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

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

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

четвертый пункт это подвариант первого пункта
plus = lambda a,b: (a==b) and  2*a or int((a**2-b**2)/(a-b))

Вероятно "правильными" вариантами являются "минус на минус", сложение степеней, sum и, например, operator или eval, хотя мне больше нравится по длине строки. Это натолкнуло на ещё один простой ответ - цикл по b и a += 1, ведь это же другой оператор?

А если так, то можно и ещё проще: a += b

Ребята, мы тут в корпорации тоже решили оказаться от плюсов. Подскажите, какой из вариантов самый быстрый и жрет мало памяти???
Видишь ошибку? Она здесь есть. И на интервью её заметят. Но не будем пока отвлекаться — в конце объясню.
Это тестирование кратковременной памяти, или будет вторая статья в цикле?

Без плюса? Ха! Можно сложение сделать даже без самих чисел! :)


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


Навскидку:


# Вспомогательная функция
rec = lambda f: f(f)

# Определение «числа»
zero = lambda: None
succ = lambda x: lambda: x

# Сложение «чисел»
add_num = rec(lambda r: lambda x, y: x if not y() else r(r)(succ(x), y()))

# Преобразование в «число»
to_num = lambda n: (lambda l: rec(lambda r: lambda a: succ(a) if not next(l) else r(r)(succ(a))))(iter(reversed(range(n))))(zero)

# Преобразование из «числа»
ln = lambda i: next(iter(next(iter(reversed(list(enumerate(i)))))))
from_num = lambda num: ln(rec(lambda r: lambda n, l: l if not n() else r(r)(n(), [*l, []]))(num, [[]]))

# Сложение
add = lambda x, y: from_num(add_num(to_num(x), to_num(y)))

# Проверяем
add(5, 3) # выведет 8

Интересно, тот работодатель взял бы меня писать код в продакшен? :)

Разве что этого работодателя будут звать David Beazley.

Вообще, конечно, впечатляет.

Сходу вспомнилось

abs(-a-b)

~(-a-b)+1

Python — это язык программирования, с помощью которого в начале 21 века складывали два целых числа.
На всякий случай
Барометр — это прибор, с помощью которого в конце 20 века измеряли высоту башен. (с)
a = 7
b = 9
while a:
  a = ~-a
  b = -~b
print(b)
# 16
Великолепно!
Вариант использовать список предвыделенных интов (которые от -5 до 256), взять адрес a и пробежаться по списку циклом из b раз уже был? :)
«Три точки в первой строке — это Ellipsis?»
Да. Объект-заполнитель, который здесь используется вместо pass. Появился в последних версиях.

Интересно, начиная с какой?

Точно версию не скажу, но в Python 2.7 многоточие уже было, но можно было использовать только при индексирования. Начиная с Python 3.0 (декабрь 2008 года) многоточие уже можно использовать как самостоятельный объект.

Ну и стоит добавить, конечно, что многоточие (объект) конечно же не является заменой pass (элемент синтаксиса) и вводился совсем для других целей.

Если у вас нету плюсов - пишите на чистом Си. Ну или собирайте компилятор плюсов самостоятельно)

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории