views:

321

answers:

8

I am trying to reverse the order of words in a sentence by maintaining the spaces as below.

[this is my test    string] ==> [string test my is    this]

I did in a step by step manner as,

[this is my test    string] - input string
[gnirts    tset ym si siht] - reverse the whole string - in-place
[string    test my is this] - reverse the words of the string - in-place
[string test my is    this] - string-2 with spaces rearranged

Is there any other method to do this ? Is it also possible to do the last step in-place ?

+1  A: 

For words from first to central words switch word n with word length - n First use a split function and then do the switching

GôTô
A: 

I think I'd just tokenize (strtok or CString::Tokanize) the string using the space character. Shove the strings into a vector, than pull them back out in reverse order and concatenate them with a space in between.

Charles
with a little cleanup to your logic on finding the intermediary spaces (has to retain original space ordering) I would to just this
drachenstern
How would this maintain multiple spaces between words, as in his example between "test" and "string"?
KeithS
-1: strtok is zomg bad and CString is not Standard C++
John Dibling
I think one of the points of this interview question is to see if the candidate can figure out how to tokenize.
John Dibling
+1  A: 

This pseudocode assumes you don't end the initial string with a blank space, though can be suitably modified for that too.

1.  Get string length; allocate equivalent space for final string; set getText=1

2.  While pointer doesn't reach position 0 of string,

    i.start from end of string, read character by character... 
      a.if getText=1 
       ...until blank space encountered
      b.if getText=0
       ...until not blank space encountered

    ii.back up pointer to previously pointed character

    iii.output to final string in reverse

    iv.toggle getText

3.  Stop
Kedar Soparkar
+3  A: 

Your approach is fine. But alternatively you can also do:

  • Keep scanning the input for words and spaces
  • If you find a word push it onto stack S
  • If you find space(s) enqueue the number of spaces into a queue Q

After this is done there will be N words on the stack and N-1 numbers in the queue.

While stack not empty do
 print S.pop
 if stack is empty break
 print Q.deque number of spaces
end-while
codaddict
A: 

All strtok-solutions work not for your example, see above. Try this:

char *wordrev(char *s)
{
  char *y=calloc(1,strlen(s)+1);
  char *p=s+strlen(s);
  while( p--!=s )
    if( *p==32 )
      strcat(y,p+1),strcat(y," "),*p=0;
  strcpy(s,y);
  free(y);
  return s;
}
Doesn't it seem a little crazy to need calloc and free to do something so conceptually simple? And you're modifying the input string?
John Dibling
Yes, i modifying it. You dont know the difference between <char*> and <const char*>?
-1: it doesn't work; +0.5 it compiles ( http://codepad.org/8pQGNta3 ) -- total rounded up: 0
pmg
+1  A: 

Here's an approach.

In short, build two lists of tokens you find: one for words, and another for spaces. Then piece together a new string, with the words in reverse order and the spaces in forward order.

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <sstream>
using namespace std;

string test_string = "this is my test    string";

int main()
{
    // Create 2 vectors of strings.  One for words, another for spaces.
    typedef vector<string> strings;
    strings words, spaces;
    // Walk through the input string, and find individual tokens.
    // A token is either a word or a contigious string of spaces.
    for( string::size_type pos = 0; pos != string::npos; )
    {
        // is this a word token or a space token?
        bool is_char = test_string[pos] != ' ';
        string::size_type pos_end_token = string::npos;

        // find the one-past-the-end index for the end of this token
        if( is_char )
            pos_end_token = test_string.find(' ', pos);
        else
            pos_end_token = test_string.find_first_not_of(' ', pos);

        // pull out this token
        string token = test_string.substr(pos, pos_end_token == string::npos ? string::npos : pos_end_token-pos);
        // if the token is a word, save it to the list of words.
        // if it's a space, save it to the list of spaces
        if( is_char )
            words.push_back(token);
        else
            spaces.push_back(token);
        // move on to the next token
        pos = pos_end_token;
    }

    // construct the new string using stringstream
    stringstream ss;
    // walk through both the list of spaces and the list of words,
    // keeping in mind that there may be more words than spaces, or vice versa
    // construct the new string by first copying the word, then the spaces
    strings::const_reverse_iterator it_w = words.rbegin();
    strings::const_iterator it_s = spaces.begin();
    while( it_w != words.rend() || it_s != spaces.end() )
    {
        if( it_w != words.rend() )
            ss << *it_w++;
        if( it_s != spaces.end() )
            ss << *it_s++;
    }

    // pull a `string` out of the results & dump it
    string reversed = ss.str();
    cout << "Input: '" << test_string << "'" << endl << "Output: '" << reversed << "'" << endl;

}
John Dibling
A: 

Too bad stl string doesn't implement push_front. Then you could do this with transform().

#include <string>
#include <iostream>
#include <algorithm>

class push_front
{
public:
   push_front( std::string& s ) : _s(s) {};
   bool operator()(char c) { _s.insert( _s.begin(), c ); return true; };
   std::string& _s;
};

int main( int argc, char** argv )
{

   std::string s1;
   std::string s( "Now is the time for all good men");
   for_each( s.begin(), s.end(), push_front(s1) );

   std::cout << s << "\n";
   std::cout << s1 << "\n";
}

Now is the time for all good men

nem doog lla rof emit eht si woN

Jay
-1 That is not even close to what the OP asked
pmg
+2  A: 

I would rephrase the problem this way:

  • Non-space tokens are reversed, but preserves their original order
    • The 5 non-space tokens ‘this’, ‘is’, ‘my’, ‘test’, ‘string’ gets reversed to ‘string’, ‘test’, ‘my’, ‘is’, ‘this’.
  • Space tokens remain in the original order
    • The space tokens ‘ ‘, ‘ ‘, ‘ ‘, ‘ ‘ remains in original order between the new order of non-space tokens.

Following is a O(N) solution [N being the length of char array]. Unfortunately, it is not in place as OP wanted, but it does not use additional stack or queue either -- it uses a separate character array as a working space.

Here is a C-ish pseudo code.

work_array = char array with size of input_array
dst = &work_array[ 0 ]

for( i = 1; ; i++) {
   detect i’th non-space token in input_array starting from the back side
   if no such token {
      break;
   }
   copy the token starting at dst
   advance dst by token_size
   detect i’th space-token in input_array starting from the front side
   copy the token starting at dst
   advance dst by token_size
}

// at this point work_array contains the desired output,
// it can be copied back to input_array and destroyed
ArunSaha
+1 Good general approach, though I'd break it up into while !NUL { 1) scan for size of next text block 2) copy text to new buffer 3) copy space by space }. No point counting the spaces before copying them.
Tony