Pull to refresh

Comments 31

 print(i * 100 + j * 10 + k)
Зачем тут умножение?

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

который выводит числа от 0 до 1000, которые делятся на 3

Способ вывода не написан, возможно это сериализация для которой важен тип данных. Но слово "числа" намекает что нужен int.

Начал с тройки, но почему упустил 1000, оно же не делится на три. Кандидат думает, но не вникает в детали.

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

for (int i = 3; i <= 1000; i += 3) {

Этот цикл заканчивается на 999

Да, на месте кандидата я бы так и ответил, но тогда он скажет - а зачем тогда <= когда можно обойтись <

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

но ведь в условии явно записана 1000? как объяснить потом, что она должна превратиться в 999? И мы ведь не экономим "=".

Можно было вообще на 900 закончить

У всех чисел от 900 до 999 сумма цифр заведомо не меньше 10

Но 900 делится на 5, как и 810, поэтому закончить можно на 801.

По факту достаточно закончить на 900, т.к. сумма цифр д.б. меньше 9

Интервьюер:

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

Кандидат:

**уходит с интерьвю**

Одна из задач, которую мы даём соискателям: написать код, который выводит числа от 0 до 1000, которые делятся на 3, но не делятся на 5, и сумма цифр в которых меньше десяти

...

Ну и моё решение

А оно точно выведет 9? 54? 117?

Да, автор заигрался в оптимизацию и посадил ошибку.
Его решение выдаёт 25 чисел, правильное решение «в лоб» — 65.

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

Вопрос в том, почему не исправлено в статье. Нехорошо... Как минимум коммент под решением не помешал бы.

В целом есть замечательный признак делимости на три которых отлично ложится на условия задачи в части "сумма цифр меньше 10". Но уж больно он неявно в коде сделан. Или наоборот - намеренно явно и ошибочно.

Автора бы в студию.

Не, строка

if (i + j + k != 3 && i + j + k != 6)

Неправильная

нет, не выводит, это условие не верно написано:
for (int k = 0; i + j + k < 9; ++k) if (k == 5 || k ==0) continue;
if (i + j + k != 3 && i + j + k != 6)

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

Наиболее производительное на данный момент. Более чем в два раза чем "простой" и вариант@igolikov.

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

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

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

Я, правда, в Java не писец, у меня деформация от ассемблера и С, вот второе и третье решение в ассемблер хорошо ложатся. Я бы еще даже сделал

for (int i = 3; 1 <= 1000/3; i ++)
{
  if (i % 5 != 0)
  {
    j = i*3;
    if (check(j))
    {
      System.out.println(j);
    }
  }
}

заметил ошибку, должно быть for (int i = 1; i <= 1000/3; i ++)

Тут вся сложность будет внутри функции check, которая должна разложить число j на цифры. Программист напишет это через операции div/mod 10/100, а компилятор превратит деления на 10/100 в сдвиги и умножения на «магические константы» типа 0x0CCCCCCCD, 0x66666667 и 0x51EB851F. Вроде как итераций цикла в три раза меньше, зато тело цикла раздувается. Плюс ещё проверка на кратность 5, тоже тяжелее, чем у автора. Впрочем, не исключено, что ваша версия будет быстрее.

Код автора
 for (int k = 0; i + j + k < 9; ++k)
        if (k == 5 || k == 0) continue;

можно ещё упростить
 for (int k = 1; i + j + k < 9; ++k)
        if (k == 5) continue;

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

Хотя это конечно аналитическая профдеформация уже.

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

Каждый раз, когда я вижу continue, рука тянется к киянке.


ФП сравнительно новая концепция

Гхм, Лиспу более 60 лет, Хаскелю — более 30.

Каждый раз, когда я вижу continue, рука тянется к киянке.
И return в середине функции тоже не нравится? Мы бы с вами не сработались )))

Возврат в середине функции иногда может быть оправдан, continue же — code smell в чистом виде, goto на минималках. Его обожают начинающие ждуниоры с кашей в голове.


Мы бы с вами не сработались )))

Открывающую фигурную скобку вы где ставите, заветам Кернигана и Ритчи следуете?

Думается мне continue настолько же goto, насколько while является return'ом.
Пример кода из свежей Symfony:

foreach ($transitions as $transition) {
    if ($transition->getName() !== $transitionName) {
        continue;
    }

    $transitionBlockerList = $this->buildTransitionBlockerListForTransition($subject, $marking, $transition);

    if ($transitionBlockerList->isEmpty()) {
        return true;
    }
}

Там далеко не джуниоры пишут проект, как мне кажется.

continue же — code smell в чистом виде, goto на минималках. Его обожают начинающие ждуниоры с кашей в голове
Как-то я себе слабо представляю, что человек писал-писал break и continue, и тут его осенило: всё, хватит! Я теперь буду создавать новый блок вложенности, чтобы всё было явно прописано.

В моей же картине мира, противники continue — это либо такие старые бабки, которые учились на turbo pascal 2.0, где не было этой конструкции, и которые ворчат «не нужны нам ваши лямбды, и continue ваш сраный нам тоже не нужон!».

Либо такие математики-теоретики, адепты Вирта, которые любой код приводят к стандартным блокам «следования, ветвления, итерации». У них всё должно быть по строгим теоретическим схемам. Если уж пишем императивный код, то никакой декларативности, и наоборот.

Против break никто не возражал, речь шла исключительно про continue.


не нужны нам ваши лямбды

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


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

Где continue, а где декларативность, не сравнивайте тёплое с мягким.

Против break никто не возражал, речь шла исключительно про continue.
И то, и другое — скрытый goto. Есть рациональная причина, почему одно можно, а другое нельзя?

Если уж доводить до абсурда
Почему же? Лямбды — синтаксический сахар, как и continue, их можно выразить в старых конструкциях, но громоздким и избыточным кодом.

Кандидат знает, как работают процессоры.

Какая именно особенность работы процессора использована в том коде?

Ну и моё решение

А что 9 18 27 и тд не подходят ? Ваше решение их не выводит

Sign up to leave a comment.

Articles