Украинское сообщество программистов

Трудный вопрос на собеседовании #3

Александр Скакунов
Опубликовано 16.06.2008 в Статьи

Продолжаем серию переводов цикла “Трудные вопросы на собеседовании“.

Задача #3

Как вы обернете порядок слов (не символов) в строке длиной n при постоянном объеме дополнительной памяти (constant extra space) за линейное время (linear time)?

UPDATE: ответ.

Теги: ,

1 звезда2 звезды3 звезды4 звезды5 звезд (12 голосов, средний: 2.58 из 5)
Загрузка ... Загрузка ...
Распределение голосов

Понравилась статья? Подпишись на обновления по RSS/E-mail

Подписаться, не оставляя комментарий

Все комментарии (40) к “Трудный вопрос на собеседовании #3” RSS

  1. Раковець Олександр

    Я б виділяв по слову з початку та кінця рядка, а тоді міняв їх місцями через додаткову пам’ять. І так, до зустрічі вказівників у середині рядка.
    Хоча, я не до кінця зрозумів обмеження constant extra space.

  2. mstar

    pregsplit на слова и реверс массива слов.

    На счет памяти тоже не понял, что имелось в виду? кол-во байт и операции только с массивом символов?

  3. Скакунов Александр

    Насколько я могу судить, “constant extra space” – расхожее понятие в области сортировки. Есть даже книжка “Constant-space string-matching“:

    it [string-matching algorithm] processes the searched text with constant memory space in addition to the string

  4. Алексей

    Пусть есть такая функция оборота части строки (псевдокод, str – строка, s – начальный индекс, e – конечный):
    function reverse(str, s, e) {
    for(i = s; i < e/2; i++) {
    buf = str[i];
    str[i] = str[e - i + 1];
    str[e - i + 1] = buf;
    }
    }

    Первым делом оборачиваем всю строку:
    reverse(str, 0, n)

    Затем последовательно находим границы слов (s_word, e_word) и для каждого вызываем:
    reverse(str, s_word, e_word)

    Вот как-то так примерно

  5. Алексей

    Sorry за отвутствие отступов, пробую еще раз только функцию:

    
    function reverse(str, s, e) {
      for(i = s; i < e/2; i++) {
        buf = str[i];
        str[i] = str[e - i + 1];
        str[e - i + 1] = buf;
      }
    }
  6. Алексей

    Хм… я ожидал что code сохранит форматирование

  7. Алексей

    Да, добавлю сразу – str передается в функцию по ссылке.

  8. the que

    ruby:
    string.split.reverse.join(” “) :)

  9. Скакунов Александр

    string.split.reverse.join(” “)

    Прикольно :)
    Правда, не соблюдено условие задачи – “constant extra space”, т.к. используется массив переменной длины.

  10. serge lorich

    если используется массив той же длины что и строка, то это constant extra space?
    оценка времени выполнения меня удручает :)

  11. Andrey

    Перевертнуть всю строку, а потом перевернуть символы в каждом слове.

  12. Olexiy

    C++

    // Вважаємо, що слова в рядку розділяються пробілами.
    void f(string& s) {
      reverse(s.begin(), s.end());
      int prev = 0;
      for (int i = 0; i < s.length(); i++)
        if (s[i] == ' ') {
          reverse(s.begin() + prev, s.begin() + i);
          prev = i;
        }
      reverse(s.begin() + prev, s.end());
    }
  13. Olexiy

    Упс, все-таки треба тестити спочатку.

    void f(string& s) {
        reverse(s.begin(), s.end());
        int prev = -1;
        for (int i = 0; i < s.length(); i++)
            if (s[i] == ' ') {
                reverse(s.begin() + prev + 1, s.begin() + i);
                prev = i;
            }
    
        reverse(s.begin() + prev + 1, s.end());
    }
  14. Olexiy

    >> если используется массив той же длины что и строка, то это constant extra space?

    це linear extra space.

  15. Скакунов Александр
    если используется массив той же длины что и строка, то это constant extra space?

    це linear extra space

    Поприветствуем Олексия Орешко, координатора TopCoder!

    Олексий, могли бы вы авторитетно объяснить, что такое этот constant extra space? Ибо народ конфузится, хотя ответы пишет правильные.

  16. Olexiy

    Константна додаткова пам’ять (constant extra space) – розмір якої не залежить від розміру вхідних даних.

    Лінійна додаткова пам’ять (constant extra space) – розмір якої лінійно залежить від розміру вхідних даних.

    Звичайно, всі ці визначення мають на увазі пам’ять у найгіршому для вашої програми випадку.

    Простими словами. Візьмемо вхідні дані (в нашому випадку – рядок) і почнемо їх збільшувати (дописувати до рядка символи). Якщо при кожному збільшенні рядка в два рази пам’ять збільшиться вдвічі – то це лінійна залежність. Якщо не зміниться ніяк – то пам’ять константна. Аналогічно з часом виконання.

  17. Sasha

    Спробую пояснити на пальцях про “constant extra space”.

    Якщо вашій програмі для обробки вхідних даних довжиною в одну букву (1 слово з однієї букви) необхідно виділити блоки пам’яті сумарним розміром в 1 МБ але коли на вхід передали стрічку, що містить 4 Мільярди слів по 100 букв у кожному слові – програмі все ще буде достатньо цього ж 1 МБ додаткової пам’яті.

    У випадку
    ruby:
    string.split.reverse.join(” “)

    Потрібно буде виділити масив, розмір якого залежить від вхідних даних а також створити копії всіх слів в стрічці і помістити їх у цей масив. Відповідно, оцінити розмір додаткової мам’яті не знаючи розміру вхідної стрічки – неможливо.

  18. Olexiy

    2 Саша
    >>Відповідно, оцінити розмір додаткової мам’яті не знаючи розміру вхідної стрічки – неможливо.

    Наскільки я зрозумів, то пам’ять має бути лінійна як мінімум (копія всього ). Хоча, з іншого боку, мова програмування може оптимізувати деякі операції.

  19. Olexiy

    Формальне визначення константної додаткової пам’яті.
    Пам’ять константна (не залежить від входу), якщо існує такий об’єм пам’яті Х, що ваша програма не потребуватиме більше Х при жодних вхідних даних.

    Пам’ять лінійна, якщо існує таке число Х, що ваша програма ніколи не потребуватиме більше, ніж Х * (розмір вхідних даних).

    >> Раковець Олександр
    Я б виділяв по слову з початку та кінця рядка, а тоді міняв їх місцями через додаткову пам’ять.

    Тут обмеження на пам’ять може бути лінійним, якщо дати на вхід одне величезне слово (рядок без пробілів). Крім того, не розкрита тема обміну місцями слів різної довжини.

  20. Oleksiy Glib

    похоже на задачки с алгоритмической олимпиады…

  21. Сергей
    
      char* str = "Hello my dear friend . How are you ?";
      Memo1->Lines->Add(str);
      Memo1->Lines->Add("---------------------------");
      unsigned nF = 0;
      unsigned nL = 0;
      unsigned len = strlen(str);
      for(unsigned i = 0; i Lines->Add(str);
    
  22. Сергей
    char* str = "Hello my dear friend . How are you ?";
      Memo1->Lines->Add(str);
      Memo1->Lines->Add("---------------------------");
      unsigned nF = 0;
      unsigned nL = 0;
      unsigned len = strlen(str);
      for(unsigned i = 0; i Lines->Add(str);
  23. Сергей
    {
        if(str[i] == ' ')
        {
          nF = nL;
          nL = i - 1;
          reverse(str,nF,nL);
          nL +=2;
        }
      }
      reverse(str,nL,len-1);
    
      reverse(str,0,len-1);
      Memo1->Lines->Add(str);
  24. Сергей

    Сорри за пост 21. 22+23 моё решение.
    P.S: Непонимаю почему в один не влезает..=(

  25. Сергей

    Хмм…цикл такой for(unsigned i = 0; i < len; ++i)…

  26. Sasha

    2 Olexiy
    >> Наскільки я зрозумів, то пам’ять має бути лінійна як мінімум (копія всього ).
    Копію всього робити непотрібно, оскільки результат роботи ф-ї записується в той же масив, де були вхідні дані.

    >> Мова програмування може оптимізувати деякі операції.
    Оптимізувати може компілятор (а не мова програмування). Оптимізація НІКОЛИ не рообить з неправильної програми – правильну і не змінює складність алгоритму (лінійний, логарифмічний).
    Компілятор може лише замінювати деякі елементарні (з точки зору мови програмування) операції на еквівалентні або ж викидати частини коду що не впливають на результат.

  27. Olexiy

    2 Саша
    >> Потрібно буде виділити масив, розмір якого залежить від вхідних даних а також створити копії всіх слів в стрічці і помістити їх у цей масив.

    Наскільки я зрозумів це речення, то копії всіх слів одночасно перепишуться в масив – тобто, власне, весь вміст входу (за виключенням пробілів) буде переписано.

    Щодо оптимізації – я мав на увазі, що деталі реалізації можуть суттєво відрізнятись. Крім того, якщо ми використовуємо деякі бібліотечні методи, то деталі їх реалізації, очевидно, напряму впливає на складність кінцевої програми.

  28. raggzy

    Как я понял условие:
    Есть только ваша строка, никакой дополнительной памяти (даже копии строки), кроме како-то константного (5-10) кол-ва переменных (long”ов, например) быть не может.

    Таким образом, строку нельзя ни разрезать, ни вставлять в нее ничего. Можно лишь только менять 2 символа с i и j позиций.

    В таком ракурсе решение:
    1. Просто развернуть строку

    for (long i = 0; i < n/2; i++) {char a=s[i]; s[i] = s[n-i-1]; s[n-i-1]=a)

    Кому не нравится, можете вынести char a за цикл.
    Всего : Один проход по строке.
    2. В полученной строке поразворачивать слова.
    Это реализуется с помощью двух указателей, первый – на начало слова, другой на конец. Разворот такой же, как и в пункте 1.

    long i,j = 0;
    while true
    {
    while ((i < n) and whitespace(s[i])) i++; // передвигаем первый в начало слова
    if (i==n) break;
    j=i+1;
    while ((j  "milk want I" -> "milk want I"
  29. raggzy

    Еще раз алгоритм, бо система делает текст по дыбильному написанным :)

    long i,j = 0;
    while true
    {
      while ((i < n) and whitespace(s[i])) i++; // передвигаем первый в начало слова
      if (i==n) break;
      j=i+1;
      while ((j < n) and !whitespace(s[j])) j++;
      reverse(s,i,j);// разворот найденого слова
      i=j;// переход к новому слову
    }

    Всего 3 прохода по строке. (1 – пункт один, 2 и 3-в вайле, просто разворот каждого слова по сути добавляет еще один проход)

  30. raggzy

    чуваки сорри за and, должно быть &&, привык у ся передефайнивать :)

  31. raggzy

    Эх. оказуется, ее уже решили идейно в посте 11….сорри за офтоп :)

  32. Olexiy

    2 raggzy: Співбесіда ж на ІТ-позицію, а не на філолога – так що код потрібен :)

  33. еуе

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

  34. Щетинин Сергей

    @ай,
    5 баллов ))

  35. Olexiy

    2 raggzy
    У тебе, до речі, якщо рядок (після розвороту) закінчується словом, то це останнє слово буде написано ззаду наперед. Приклад: на “ab cd” видасть “cd ba”.

  36. Olexiy

    2 Щетинин
    Привіт Малюк, як життя?

  37. Щетинин Сергей

    Привет Орех, дела хорошо, как у тебя?

  38. aRt

    Да… помню задавал на собеседовании такую задачку )) пока что результат 50% .. правда решил ее давать только 2 челам )) обычно до нее дело не доходит..

  39. Скакунов Александр

    Итак, правильный ответ:

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

    Затем обратите порядок символов в каждом слове. Теперь буквы в словах располагаются в изначальном порядке (т.к. они были обращены два раза), но слова находятся в обратном порядке (первое слово – в конце, и т.д.)

    За проявленную активность администрация developers.org.ua рада вручить футболку Олексию Орешко.

  40. biltar

    Це буде більше ніж лінійний час, чи я помиляюся?

Оставить комментарий

Указать свой сайт могут только зарегистрированные пользователи. Регистрация или вход.

Архив

Добавить статью

Станьте автором нашего сайта!

Какие материалы подходят для публикации? — Такие.

Присылайте статьи на editors@developers.org.ua.

Подробнее.

Популярные теги

Все теги

Комментарии

Последние комментарии

интернет магазин бытовая техника магазин Laptoper