Эффективно изменить порядок слов (не символов) в массиве символов

учитывая массив символов, который формирует предложение слов, дайте эффективный алгоритм для изменения порядка слов (а не символов) в нем.

пример ввода и вывода:

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

это должно быть O(N) время и O (1) пространство (split() и нажатие на / выскакивание стека не допускается).

головоломка взята из здесь.

8 ответов


решение на C / C++:

void swap(char* str, int i, int j){
    char t = str[i];
    str[i] = str[j];
    str[j] = t;
}

void reverse_string(char* str, int length){
    for(int i=0; i<length/2; i++){
        swap(str, i, length-i-1);
    }
}
void reverse_words(char* str){
    int l = strlen(str);
    //Reverse string
    reverse_string(str,strlen(str));
    int p=0;
    //Find word boundaries and reverse word by word
    for(int i=0; i<l; i++){
        if(str[i] == ' '){
            reverse_string(&str[p], i-p);
            p=i+1;
        }
    }
    //Finally reverse the last word.
    reverse_string(&str[p], l-p);
}

Это должно быть o(n) по времени и O(1) в пространстве.

Edit: немного очистил его.

первый проход над строкой, очевидно, O(n/2) = O (n). Второй проход-O(N + комбинированная длина всех слов / 2) = O(n + n/2) = O(n), что делает этот алгоритм o (n).


нажатие строки на стек, а затем ее выкидывание-это все еще O (1)? по сути, это то же самое, что и использование split()...

не за O(1) означает? Эта задача становится легкой, если мы можем просто добавлять строки и прочее, но это использует пространство...

редактировать: Томас Уотнедал прав. Следующий алгоритм-O (n) во времени и O (1) в пространстве:

  1. обратная строка на месте (первая итерация по строке)
  2. обратный каждой (reversed) word in-place (еще две итерации по строке)
    1. найти первое слово граница
    2. обратный внутри этого слова границы
    3. повторите для следующего слова до конца

Я думаю, нам нужно будет доказать, что Шаг 2 действительно только O(2n)...


#include <string>
#include <boost/next_prior.hpp>

void reverse(std::string& foo) {
    using namespace std;
    std::reverse(foo.begin(), foo.end());
    string::iterator begin = foo.begin();
    while (1) {
        string::iterator space = find(begin, foo.end(), ' ');
        std::reverse(begin, space);
        begin = boost::next(space);
        if (space == foo.end())
            break;
    }
}

вот мой ответ. Никаких вызовов библиотек и временных структур данных.

#include <stdio.h>

void reverse(char* string, int length){
    int i;
    for (i = 0; i < length/2; i++){
        string[length - 1 - i] ^= string[i] ;
        string[i] ^= string[length - 1 - i];
        string[length - 1 - i] ^= string[i];
    }   
}

int main () {
char string[] = "This is a test string";
char *ptr;
int i = 0;
int word = 0;
ptr = (char *)&string;
printf("%s\n", string);
int length=0;
while (*ptr++){
    ++length;
}
reverse(string, length);
printf("%s\n", string);

for (i=0;i<length;i++){
    if(string[i] == ' '){
       reverse(&string[word], i-word);
       word = i+1;
       }
}   
reverse(&string[word], i-word); //for last word             
printf("\n%s\n", string);
return 0;
}

в псевдо код:

reverse input string
reverse each word (you will need to find word boundaries)

@Daren Thomas

реализация вашего алгоритма (O (N) во времени, O (1) в пространстве) В D (цифровой Марс):

#!/usr/bin/dmd -run
/**
 * to compile & run:
 * $ dmd -run reverse_words.d
 * to optimize:
 * $ dmd -O -inline -release reverse_words.d
 */
import std.algorithm: reverse;
import std.stdio: writeln;
import std.string: find;

void reverse_words(char[] str) {
  // reverse whole string
  reverse(str);

  // reverse each word
  for (auto i = 0; (i = find(str, " ")) != -1; str = str[i + 1..length])
    reverse(str[0..i]);

  // reverse last word
  reverse(str);
}

void main() {
  char[] str = cast(char[])("this is a string");
  writeln(str);
  reverse_words(str);
  writeln(str);
}

выход:

this is a string
string a is this

в Ruby

"это строка".расщеплять.обратный.присоединяйтесь ("")


В C: (C99)

#includ