Efficiently reverse the order of the words (not characters) in an array of characters

30,797

Solution 1

A solution in 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);
}

This should be O(n) in time and O(1) in space.

Edit: Cleaned it up a bit.

The first pass over the string is obviously O(n/2) = O(n). The second pass is O(n + combined length of all words / 2) = O(n + n/2) = O(n), which makes this an O(n) algorithm.

Solution 2

pushing a string onto a stack and then popping it off - is that still O(1)? essentially, that is the same as using split()...

Doesn't O(1) mean in-place? This task gets easy if we can just append strings and stuff, but that uses space...

EDIT: Thomas Watnedal is right. The following algorithm is O(n) in time and O(1) in space:

  1. reverse string in-place (first iteration over string)
  2. reverse each (reversed) word in-place (another two iterations over string)
    1. find first word boundary
    2. reverse inside this word boundary
    3. repeat for next word until finished

I guess we would need to prove that step 2 is really only O(2n)...

Solution 3

#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;
    }
}

Solution 4

Here is my answer. No library calls and no temp data structures.

#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;
}

Solution 5

In pseudo code:

reverse input string
reverse each word (you will need to find word boundaries)
Share:
30,797
jfs
Author by

jfs

isidore.john.r at gmail dot com

Updated on July 09, 2022

Comments

  • jfs
    jfs almost 2 years

    Given an array of characters which forms a sentence of words, give an efficient algorithm to reverse the order of the words (not characters) in it.

    Example input and output:

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

    It should be O(N) time and O(1) space (split() and pushing on / popping off the stack are not allowed).

    The puzzle is taken from here.