В новый выпуск ITренировки вошли задачи от «синего гиганта», компании IBM.

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

Вопросы


  1. Chickens
    A farmer sold a few chickens to four different customers on a particular day. It was such that each customer purchased half of the remaining chickens and a half chicken more.

    Can you find out how many chicken were sold by the farmer on that day if we tell you that the fourth customer bought a single chicken ?

    Перевод
    За один день фермер продал несколько цыплят четырем покупателям. Так вышло, что каждый из них купил половину остававшихся цыплят и ещё полцыплёнка.

    Можете ли Вы сказать, сколько цыплят было продано в этот день, если известно, что 4-ый покупатель купил целого цыпленка?

  2. Bullets and revolver
    A Russian gangster kidnaps you. He puts two bullets in consecutive order in an empty six-round revolver, spins it, points it at your head and shoots. *click* You’re still alive. He then asks you, “do you want me to spin it again and fire or pull the trigger again right away?” For each option, what is the probability that you’ll be shot?

    Перевод
    Вас похитил русский бандит (ох уж эти стереотипы!). Он последовательно вставил 2 пули в шестизарядный револьвер, прокрутил барабан, прицелился Вам в голову и спустил курок. *щёлк*. Вы всё ещё живы. Бандит спросил Вас — «Вы желаете, чтобы я прокрутил ещё раз и выстрелил, или выстрелил немедленно?». Какова вероятность быть застреленным в каждом случае?

Задачи


  1. Sort a stack using recursion
    Given a stack, the task is to sort it using recursion. Use of any loop constructs like while, for..etc is not allowed. We can only use the following ADT functions on Stack S:

    is_empty(S): Tests whether stack is empty or not.
    push(S): Adds new element to the stack.
    pop(S): Removes top element from the stack.
    top(S): Returns value of the top element. Note that this function does not remove element from the stack.

    Example:

    Input: -3 < — Top
    14
    18
    -5
    30

    Output: 30 < — Top
    18
    14
    -3
    -5

    Перевод
    Дан стек, задача — отсортировать его с помощью рекурсии. Использование циклических конструкций, вроде while, for… и др. запрещено. Позволено использовать только следующие абстракные команды на стеке S:

    is_empty(S): Проверяет, пуст ли стек.
    push(S): Добавляет новый элемент в стек.
    pop(S): Снимает верхий элемент стека.
    top(S): Возвращает значение верхнего элемента. Обратите внимание, что элемент не удаляется при этом.

    Примеры:

    Вход: -3 < — Вершина стека
    14
    18
    -5
    30

    Выход: 30 < — Вершина стека
    18
    14
    -3
    -5

Word breaker
Given an input string and a dictionary of words, find out if the input string can be segmented into a space-separated sequence of dictionary words. See following examples for more details.

Consider the following dictionary
{ i, like, sam, sung, samsung, mobile, ice,
cream, icecream, man, go, mango}

Input: ilike
Output: Yes
The string can be segmented as «i like».

Input: ilikesamsung
Output: Yes
The string can be segmented as «i like samsung»
or «i like sam sung».

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

Дан следующий словарь:
{ i, like, sam, sung, samsung, mobile, ice,
cream, icecream, man, go, mango}

Строка: ilike
Выход: Да. Строка может быть разбита на «i like».

Строка: ilikesamsung
Output: Да. Строка может быть разбита на «i like samsung» или «i like sam sung».

Tile Stacking Tower
A stable tower of height n is a tower consisting of exactly n tiles of unit height stacked vertically in such a way, that no bigger tile is placed on a smaller tile. An example is shown below:
          [ 1 ]
       [    2    ]
    [       3       ]
[          4           ]

We have infinite number of tiles of sizes 1, 2, …, m. The task is calculate the number of different stable tower of height n that can be built from these tiles, with a restriction that you can use at most k tiles of each size in the tower.

Note: Two tower of height n are different if and only if there exists a height h (1 <= h <= n), such that the towers have tiles of different sizes at height h.

Examples:

Input: n = 3, m = 3, k = 1.
Output: 1
Possible sequences: { 1, 2, 3}.
Hence answer is 1.

Input: n = 3, m = 3, k = 2.
Output: 7
{1, 1, 2}, {1, 1, 3}, {1, 2, 2}, {1, 2, 3}, {1, 3, 3}, {2, 2, 3}, {2, 3, 3}.

Перевод
Устойчивая башня высотой n — это башня, состоящая из ровно n плиток одинаковой высоты, уложенных вертикально таким образом, что на меньшей плитке не лежит плитка большего размера. Пример:
          [ 1 ]
       [    2    ]
    [       3       ]
[          4           ]

У нас имеется бесконечное количество плиток размеров 1, 2,..., m. Задача — рассчитать количество возможных стабильных башен высотой n, которые могут быть построены из этих плиток, с учетом того, что Вы можете использовать не более k плиток каждого размера в башне.

Обратите внимание: две башни высотой n различны только тогда, когда существует такая высота h (1 <= h <= n), что башни имеют плитки разных размеров на высоте h.

Примеры:

Вход: n = 3, m = 3, k = 1.
Выход: 1
Возможная последовательность: { 1, 2, 3}. Ответ — 1.

Вход: n = 3, m = 3, k = 2.
Выход: 7
{1, 1, 2}, {1, 1, 3}, {1, 2, 2}, {1, 2, 3}, {1, 3, 3}, {2, 2, 3}, {2, 3, 3}.

Ответы будут даны в течение следующей недели — успейте решить. Удачи!

Комментарии (45)


  1. qw1
    03.06.2018 12:05

    Задача chickens

    Скрытый текст
    Обозначим XN — кол-во перед продажей N-му покупателю.
    Тогда XN=XN/2 + 0.5 + XN+1.
    Знаем, что X5=0 (5-му покупателю ничего не осталось), получаем
    X4=1, X3=3, X2=7, X1=15.
    Ответ: 15


    1. MaxVetrov
      03.06.2018 13:49

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


      1. qw1
        03.06.2018 20:01

        Да, действительно. Но тут ещё проще. В условии сказано, что последнему достался один, отсюда X4=1


        1. MaxVetrov
          03.06.2018 20:21

          Я это я уже понял. Просто логику не нашел в резком переходе на X5 :)

          Знаем, что X5=0
          .


          1. MaxVetrov
            03.06.2018 20:44

            PS. X5 — не машина. :)


  1. qw1
    03.06.2018 12:07

    Про револьвер

    Скрытый текст
    Лучше стрелять второй раз. Так вероятность выжить 1/2, а если покрутить барабан ещё раз — 1/3


    1. AlexTest
      03.06.2018 19:05

      Если стрелять второй раз, то у вас уже не играет пустая камора барабана, выпавшая в первый раз. Т.е. у вас играют два патрона в пяти каморах. А если крутануть барабан, то у вас играет еще раз эта же пустая камора, т.е. у вас снова два патрона в шести каморах. Вероятность быть убитым без прокрутки 2/5, с прокруткой 2/6, т.е. с прокруткой вероятность быть убитым — меньше.


      1. AlexTest
        03.06.2018 19:16

        Даже еще хуже, после первого выстрела у вас уже не играют две каморы, т.к. мы знаем что патроны заряжены последовательно. Т.е. шанс быть убитым без прокрутки — 1/2, а с прокруткой — 1/3, т.е. надо крутить, чтобы шанс выжить был выше.


      1. Rsa97
        03.06.2018 20:36

        Если в первый раз выстрела не было, значит выпало одно из четырёх пустых гнёзд. Гнёзда эти идут подряд, причём после трёх из них снова пустое гнездо, после четвёртого — патрон. Следовательно, вероятность выстрела без прокрутки барабана — 1/4.


        1. AlexTest
          03.06.2018 21:29

          да, ваше рассуждение вернее моего — после первой осечки в этом случае крутить не надо!


  1. Rsa97
    03.06.2018 12:54
    +1

    Вопрос 1
    Пусть Ni — остаток перед продажей i-му покупателю. Тогда:
    Четвёртый: N4/2 + 1/2 = 1 ? N4 = (1 — 1/2) * 2 = 1
    Третий: N3 — N3/2 — 1/2 = 1 ? N3/2 = 3/2 ? N3 = 3
    Второй: N2 — N2/2 — 1/2 = 3 ? N2/2 = 7/2 ? N2 = 7
    Первый: N1 — N1/2 — 1/2 = 7 ? N1/2 = 15/2 ? N1 = 15
    Ответ: 15 кур


    1. Ellias
      04.06.2018 09:57

      Если всё таки прочитать задачу до конца, то нужно посчитать сколько всего было продано кур за день, а не сколько первый купил. Итого из вашего расчета ответ: 15+7+3+1 = 26.
      Простенькая проверка, исходя из условий задачи: будем делить пополам и прибавлять 0,5 курицы.
      1: 26/2 + 0,5 = 13,5 (12,5 в остатке)
      2: 12/2 + 0,5 (та что в остатке оставалась) = 6,5 (6 в остатке)
      3: 6/2 + 0,5 = 3,5 (2,5 в остатке)
      4: 2/2 + 0,5 = 1,5 (1 в остатке) или 2/2 = 1 (1,5 в остатке)
      То есть, всё сходится, хоть значения N и не совпадают (про то, что у продавца куриц не осталось ни одной курицы в условии ничего нет, значит всё ок).
      В задаче есть противоречие, либо это просто исключение, что последний купил одну курицу, но при этом ВСЕ купили половину и ещё пол курицы.
      Странно, но кажется ответом может быть и 19 куриц (если принимать, что половина от нечётного числа куриц это округление до чётного числа в меньшую сторону):
      1 купил 9,5
      2 купил 4,5
      3 купил 2,5
      4 купил 1,5 (или одну)


      1. Rsa97
        04.06.2018 10:16

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


        1. Ellias
          04.06.2018 12:36

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


          1. MaxVetrov
            04.06.2018 12:58

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


  1. MaxVetrov
    03.06.2018 16:32
    +1

    Цыплята

    Решение
    Обозначим:

    image — количество проданных цыплят i-му покупателю
    image — количество цыплят у фермера перед покупкой i-го покупателя
    image — общее количество покупателей

    Тогда, из условия задачи:

    image

    Найти:

    image

    Решение:
    Так как image, то при image, мы получаем image

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

    image

    Подставим, image в image

    Получаем,

    image

    Выразим image через image

    image

    Либо,

    image

    Ну и начинаем подставлять до нахождения image

    image
    image
    image
    image

    Ответ: 15


    1. MaxVetrov
      03.06.2018 17:18

      Хотя еще проще :) Не нужно подставлять до нахождения image
      Если бы покупателей было 1000, то получаем количество проданных цыплят:

      image

      т.е.

      image


      1. MaxVetrov
        03.06.2018 17:35

        Ошибся, правильный ответ:

        image

        т.е.

        image


  1. nasl
    03.06.2018 17:20

    В первой задаче не очень понятен вопрос в плане целочисленности действия «половина оставшихся кур и еще пол куры». Очевидное решение, двигаться верх по значению 2^n — 1, может быть не очень правильным. Согласитесь, попросив у продавца выдать половину оставшихся кур и пол куры из 15 штук, вряд ли он выдаст вам 8 штук:) Хотя чисто математически это верно.

    Предлагаю другое решение:
    У продавца было 12 целых кур и пол куры;
    Первому он отдал 6 целых кур (половину от оставшихся 12 целых) и пол куры, осталось 6 целых кур;
    Второму отдал 3 (половину от оставшихся 6 целых) и еще пол куры, осталось 2 целых куры и пол куры;
    Третьему отдал 1 (половину от оставшихся 2 целых) и еще пол куры, осталось 1 целая кура;
    Вот четвертому и осталась одна целая кура


    1. MaxVetrov
      03.06.2018 18:19

      Вроде все понятно:

      Половина от 15 есть 7.5, если к этому еще 0.5 добавить то первый покупатель получает 8.


      1. nasl
        03.06.2018 19:18

        Я согласен, что 15 — правильный ответ! Да, просто я пытался взглянуть на условия задачи под другим углом.


        1. MaxVetrov
          03.06.2018 19:21

          ну да, половина в магазине, и в половина в математике — это разные вещи. :)))


          1. nasl
            04.06.2018 14:27

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


            1. MaxVetrov
              04.06.2018 15:09

              Поэтому люди килограммами вешают.)


    1. MaxVetrov
      03.06.2018 18:27

      А если убрать доли, и переформулировать задачу

      Так вышло, что каждый из них купил половину остававшихся цыплят и ещё полцыплёнка.


      На

      Так вышло, что каждый из них купил половину остававшихся цыплят и ещё одного цыплёнка.


      То как бы Вы поняли эту задачу?


      1. nasl
        03.06.2018 19:21

        Это уже будет совсем другая задача:) Но в такомслучае, после первой же итерации, кур станет нечетное количество, если и было четсное. И тут вопрос деления пополам будет еще более интересным. И вряд ли можно будет сказать, что 7 или 8 — это будет пополам.


        1. MaxVetrov
          03.06.2018 19:36

          Чисто


        1. MaxVetrov
          03.06.2018 19:42

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

          У фермера есть 15 цыплят, берем половину от 15+0.5=15.5

          И получаем либо 7 либо 8 :)))
          Либо 7.25 :)


    1. tashihu
      04.06.2018 14:22

      У вас к третьему покупателю остается 2.5 курицы. Следуя условиям задачи он должен был купить 2.5/2 + 0.5 = 1.75. А 4 останеться только 0.75 курицы.


      1. nasl
        04.06.2018 14:36

        Да нет же, я предложил условие задачи интерпретировать не как [N/2 + 0.5], а говоря языком, например, матлаба [fix(N)/2 + 0.5], т.е. половину берем от целого количества куриц.
        P.s. Но как мы выяснили выше, при текущем решении значения fix(N) удачно оказались четными, a с нечетными появляется некая неоднозначность при такой условии.


  1. MaxVetrov
    04.06.2018 12:58

    Револьвер

    Решение
    Револьвер

    Ох уж эти зловещие русские, Сталина хоть не приплели :))

    Имеем
    x — зарядность револьвера
    y — количество подряд вставленных пуль

    Вероятность смерти при новой прокрутке револьвера:

    P1 = y/x = 2/6 = 1/3

    Вероятность смерти без прокрутки:

    P2 = 1/(x-y) = 1/(6-2) = 1/4

    Получили:

    P1>P2

    А это значит, что нужно стрелять сразу. И лучше — в бандита. Так шансов выжить больше :))


  1. SkylineIT
    04.06.2018 14:22

    Внимательней просто читайте про цыплят и всё станет понятно.
    Мне кажется это очевидны.
    Просто включаем обратный перебор:

    4 итерация:

    • Всего осталось = 0 ц;
    • Всего было= 0 + 1 = 1 ц;


    3 итерация:
    • Всего осталось = 1 ц;
    • Всего было: (1+0,5) * 2 = 3 ц;


    2 итерация:
    • Всего осталось = 3 ц;
    • Всего было: (3+0,5) * = 7 ц;


    1 итерация:
    • Всего осталось = 7 ц;
    • Всего было: (7+0,5) * 2 = 15 ц;


    Ответ 15.
    Не знаю как вы мистически больше получаете)

    Про револьвер:

    Сидим до выстрела = вероятность 2/6 = 1/3 шанс быть убитым;
    Выживаем.

    Просим еще раз стрелять = 2/5 шанс ~ 40%
    Крутим повторно = 1/3 шанс ~ 33.3%


    1. MaxVetrov
      04.06.2018 14:28

      Вы мне написали?


      1. MaxVetrov
        04.06.2018 14:34

        Про цеплят прочитайте полностью, я общий ответ вывел при любом n(количестве покупателей).
        Там спойлер есть, откройте, если вы первый раз здесь.


        1. MaxVetrov
          04.06.2018 14:41

          PS. цИплят


          1. reci Автор
            04.06.2018 14:46

            Вы шутите?


            1. MaxVetrov
              04.06.2018 14:49

              В смысле? я с ошибкой написал — цЕплят, а не цИплят. А править коммент не успел.


              1. MaxVetrov
                04.06.2018 15:15

                Вот блин, цЫплят.)))) Очепятка. Тороплюсь.


    1. nasl
      04.06.2018 14:44

      Там и правда получается 1/4, а не 2/5. Вы видимо в условии пропустили, что пули вставлены последовательно.


    1. MaxVetrov
      04.06.2018 14:48

      А с чего Вы взяли что 2/5?


      1. SkylineIT
        04.06.2018 15:49
        +1

        А нет.
        Всё правильно писали:
        При продолжении, получается так, что в барабане остается еще 3 пустых гнезда, которые нас устраивает, а только один следующий патрон ведёт нас к фаталу.
        Соотвественно:

        • шанс выжить — 3/4;
        • шанс погибнуть — 1/4;


        При прокрутке мы возвращаемся к вероятности:
        • шанс выжить — 2/3;
        • шанс погибнуть — 1/3;


        1. MaxVetrov
          04.06.2018 15:59
          +1

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


        1. MaxVetrov
          04.06.2018 18:07

          А если 3 пули вставили подряд, то уже все равно какое решение вы примите — вероятность 50 на 50.


          1. MaxVetrov
            04.06.2018 19:13

            ан, нет, оказывается, 1/3 и 1/2 не одно и тоже, все еще больше вероятность выживания если стреляешь сразу.


  1. jmdorian
    05.06.2018 19:21

    Задача 2
    Не самое быстрое решение, наверное и на PHP, но все же работает.
    $string = 'ilikesamsung';
    
    $vocab = ['i', 'like', 'sam', 'sung', 'samsung', 'mobile', 'ice', 'cream', 'icecream', 'go', 'mango', 'and'];
    
    strContain($string, $vocab);
    
    function strContain($string, $vocab, $result = [], $start = 0) {  
      $needle = '';
      for ($i = $start; $i < strlen($string); $i++) {
        $needle .= $string[$i];
        
        foreach ($vocab as $word) {
          if ($needle == $word) {
            $result[$start] = $needle;
            if (implode('', $result) == $string) {
              print "Yes, words are: " .  implode(", ", $result) . "<br>";
            } else {
              strContain($string, $vocab, $result, $i+1);
            }
          }
        }    
      }
    }