2013-12-18 3 views
1

Есть ли какой-либо алгоритм/метод, в котором изменение строки словами может выполняться за один проход с временной сложностью O (n) и пространственной сложностью O (1).Переключение строк по слову за один проход

+2

Вы могли бы добавить простой пример ввода/вывода? – RichardPlunkett

+0

@RichardPlunkett Это разворот строк. Выберите несколько слов. –

+1

вход: Hello world output: world hello – Abhishek

ответ

1

Если мы можем получить символы в обратном порядке, и каждое слово требует не более O(1) машинных слов в памяти, то для обратного слова в один проход можно использовать O (n) -time, O (1) -пространственный алгоритм (псевдо-код):

def reverse_words(text): 
    word = [] # assume a word requires O(1) machine words 
    for character in reversed(text): # single pass (in reverse) 
     if character == ' ': 
      if word: # print non-empty word 
       print(''.join(reversed(word)), end=character) 
       word = [] 
     else: 
      word.append(character) # O(1)-time 
    if word: # print the first word (in original text) if it is not empty 
     print(''.join(reversed(word))) 

Пример:

>>> reverse_words("this is a string") 
string a is this 

Примечание: каждый символ прикоснулся дважды: первый - добавление, второй - распечатать его. Чтобы понять, почему это еще однопроходный алгоритм, представьте вместо text функцию poplast(), которая выводит (извлекает и удаляет) последний символ из последовательности символов. Если она возвращает None для пустой последовательности, то цикл будет выглядеть так:

for character in iter(poplast, None): # call `poplast()` until it returns `None` 
    # the rest is the same as in the first loop .. 

В этом случае мы не можем сделать больше, чем один проход над входом. Он разрушается на первом проходе.

возможно ли изменить исходный текст?

Да. Снова , если можно считать, что длина длинного слова постоянна (не зависит от n), т. Е. Если n растет; максимальная длина слова остается неизменной.

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

Я не могу придумать элегантную реализацию. И я не вижу смысла однопроходного требования, если у нас есть случайный доступ к вводу. Посмотрите, как реализованы tac utility or tail -r (BSD) (в этом случае строка играет роль одного слова) для очень больших файлов, которые не вписываются в память.

+0

@ Dukeling: Это единственный проход. Представьте, что 'reverse (text)' * никогда не заканчивается *. Функция все еще работает. Единственное «большое» предположение состоит в том, что слова конечны. – jfs

+0

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

+0

@ J.F.Sebastian. Если задано обращение слов, это можно сделать за один проход, но мне нужно, чтобы строка shld была обращена словами только в «одном проходе». – Abhishek

2

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

Попробуйте:

HELLO SAM 
^ 
becomes 
SAM HELLO 
    ^

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

+0

@ Dukeling: Я говорю о последнем (иначе вы бы знали, что позиция просто «n-i-1»), и я изменил этот пример, чтобы устранить любую двусмысленность. Благодаря! –

+0

Если длина слова ограничена (не зависит от 'n'), то вы можете прочитать до конца слова. И [O (n) -time однопроходный, O (1) -пространственный алгоритм возможен] (http://stackoverflow.com/a/20649255/4279). – jfs

1

Если рассматривать слово может иметь максимальное количество символов 20, мы можем достичь O (1) пространство, O (N) времени и один проход :)

public static void main(String[] args) { 

     reverse("Hello World HaHa"); 
    } 

    public static void reverse(String line) { 
     char[] stack = new char[20]; 
     int index = 0; 
     for (int i = line.length() - 1; i >= 0; i--) { 
      if (line.charAt(i) != ' ') { 
       stack[index++] = line.charAt(i); 
      } else { 
       while (--index >= 0) { 
        System.out.print(stack[index]); 
       } 
       System.out.print(' '); 
       index = 0; 
      } 
     } 
     if (index > 0) { 
      while (--index >= 0) { 
       System.out.print(stack[index]); 
      } 
     } 
    } 

Примечание: фактическая сложность времени is 2n, где n - длина строки, но один проход!

+0

Я считаю, что это тот же подход, что и [ответ J.F.] (http://stackoverflow.com/a/20649255/1711796). Заметьте [мой комментарий там] (http://stackoverflow.com/questions/20648333/string-reversal-by-word-in-single-pass?noredirect1_comment30917729_20649255). – Dukeling

+0

@Pham Trung, вы используете buffer.So это не будет содержать пространственную сложность O (1). – Abhishek

+1

@Abhishek: любой буфер фиксированного размера ('20' в этом случае), который не зависит от' n', удовлетворяет требованиям 'O (1)' space. Вы можете сказать, что код не работает, если слово больше 20 символов. Но ваш вопрос ничего не говорит о возможном размере слова. – jfs

Смежные вопросы