Reverse the ordering of words in a string

Viewed 195505

I have this string s1 = "My name is X Y Z" and I want to reverse the order of the words so that s1 = "Z Y X is name My".

I can do it using an additional array. I thought hard but is it possible to do it inplace (without using additional data structures) and with the time complexity being O(n)?

48 Answers

Reverse the entire string, then reverse the letters of each individual word.

After the first pass the string will be

s1 = "Z Y X si eman yM"

and after the second pass it will be

s1 = "Z Y X is name My"

reverse the string and then, in a second pass, reverse each word...

in c#, completely in-place without additional arrays:

static char[] ReverseAllWords(char[] in_text)
{
    int lindex = 0;
    int rindex = in_text.Length - 1;
    if (rindex > 1)
    {
        //reverse complete phrase
        in_text = ReverseString(in_text, 0, rindex);

        //reverse each word in resultant reversed phrase
        for (rindex = 0; rindex <= in_text.Length; rindex++)
        {
            if (rindex == in_text.Length || in_text[rindex] == ' ')
            {
                in_text = ReverseString(in_text, lindex, rindex - 1);
                lindex = rindex + 1;
            }
        }
    }
    return in_text;
}

static char[] ReverseString(char[] intext, int lindex, int rindex)
{
    char tempc;
    while (lindex < rindex)
    {
        tempc = intext[lindex];
        intext[lindex++] = intext[rindex];
        intext[rindex--] = tempc;
    }
    return intext;
}
Not exactly in place, but anyway: Python:

>>> a = "These pretzels are making me thirsty"
>>> " ".join(a.split()[::-1])
'thirsty me making are pretzels These'

You cannot do the reversal without at least some extra data structure. I think the smallest structure would be a single character as a buffer while you swap letters. It can still be considered "in place", but it's not completely "extra data structure free".

Below is code implementing what Bill the Lizard describes:

string words = "this is a test";

// Reverse the entire string
for(int i = 0; i < strlen(words) / 2; ++i) {
  char temp = words[i];
  words[i] = words[strlen(words) - i];
  words[strlen(words) - i] = temp;
}

// Reverse each word
for(int i = 0; i < strlen(words); ++i) {
  int wordstart = -1;
  int wordend = -1;
  if(words[i] != ' ') {
    wordstart = i;
    for(int j = wordstart; j < strlen(words); ++j) {
      if(words[j] == ' ') {
        wordend = j - 1;
        break;
      }
    }
    if(wordend == -1)
      wordend = strlen(words);
    for(int j = wordstart ; j <= (wordend + wordstart) / 2 ; ++j) {
      char temp = words[j];
      words[j] = words[wordend - (j - wordstart)];
      words[wordend - (j - wordstart)] = temp;
    }
    i = wordend;
  }
}

What language? If PHP, you can explode on space, then pass the result to array_reverse.

If its not PHP, you'll have to do something slightly more complex like:

words = aString.split(" ");
for (i = 0; i < words.length; i++) {
    words[i] = words[words.length-i];
}
public static String ReverseString(String str)
{
    int word_length = 0;
    String result = "";
    for (int i=0; i<str.Length; i++)
    {
        if (str[i] == ' ')
        {
            result = " " + result;
            word_length = 0;
        } else 
        {
            result = result.Insert(word_length, str[i].ToString());
            word_length++;
        }
    }
    return result;
}

This is C# code.

Most of these answers fail to account for leading and/or trailing spaces in the input string. Consider the case of str=" Hello world"... The simple algo of reversing the whole string and reversing individual words winds up flipping delimiters resulting in f(str) == "world Hello ".

The OP said "I want to reverse the order of the words" and did not mention that leading and trailing spaces should also be flipped! So, although there are a ton of answers already, I'll provide a [hopefully] more correct one in C++:

#include <string>
#include <algorithm>

void strReverseWords_inPlace(std::string &str)
{
  const char delim = ' ';
  std::string::iterator w_begin, w_end;
  if (str.size() == 0)
    return;

  w_begin = str.begin();
  w_end   = str.begin();

  while (w_begin != str.end()) {
    if (w_end == str.end() || *w_end == delim) {
      if (w_begin != w_end)
        std::reverse(w_begin, w_end);
      if (w_end == str.end())
        break;
      else
        w_begin = ++w_end;
    } else {
      ++w_end;
    }
  }

  // instead of reversing str.begin() to str.end(), use two iterators that
  // ...represent the *logical* begin and end, ignoring leading/traling delims
  std::string::iterator str_begin = str.begin(), str_end = str.end();
  while (str_begin != str_end && *str_begin == delim)
    ++str_begin;
  --str_end;
  while (str_end != str_begin && *str_end == delim)
    --str_end;
  ++str_end;
  std::reverse(str_begin, str_end);
}

Here is the Java Implementation:

public static String reverseAllWords(String given_string)
{
    if(given_string == null || given_string.isBlank())
        return given_string;

    char[] str = given_string.toCharArray();
    int start = 0;

    // Reverse the entire string
    reverseString(str, start, given_string.length() - 1);

    // Reverse the letters of each individual word
    for(int end = 0; end <= given_string.length(); end++)
    {
        if(end == given_string.length() || str[end] == ' ')
        {
            reverseString(str, start, end-1);
            start = end + 1;
        }
    }
    return new String(str);
}

// In-place reverse string method
public static void reverseString(char[] str, int start, int end)
{
    while(start < end)
    {
        char temp = str[start];
        str[start++] = str[end];
        str[end--] = temp;
    }
}

Actually, the first answer:

words = aString.split(" ");
for (i = 0; i < words.length; i++) {
    words[i] = words[words.length-i];
}

does not work because it undoes in the second half of the loop the work it did in the first half. So, i < words.length/2 would work, but a clearer example is this:

words = aString.split(" "); // make up a list
i = 0; j = words.length - 1; // find the first and last elements
while (i < j) {
    temp = words[i]; words[i] = words[j]; words[j] = temp; //i.e. swap the elements
    i++; 
    j--;
}

Note: I am not familiar with the PHP syntax, and I have guessed incrementer and decrementer syntax since it seems to be similar to Perl.

How about ...

var words = "My name is X Y Z";
var wr = String.Join( " ", words.Split(' ').Reverse().ToArray() );

I guess that's not in-line tho.

In c, this is how you might do it, O(N) and only using O(1) data structures (i.e. a char).

#include<stdio.h>
#include<stdlib.h>
main(){
  char* a = malloc(1000);
  fscanf(stdin, "%[^\0\n]", a);
  int x = 0, y;
  while(a[x]!='\0')
  {
    if (a[x]==' ' || a[x]=='\n')
    {
      x++;
    }
    else
    {
      y=x;
      while(a[y]!='\0' && a[y]!=' ' && a[y]!='\n')
      { 
        y++;
      }
      int z=y;
      while(x<y)
      {
        y--;
        char c=a[x];a[x]=a[y];a[y]=c; 
        x++;
      }
      x=z;
    }
  }

  fprintf(stdout,a);
  return 0;
}

Better version
Check my blog http://bamaracoulibaly.blogspot.co.uk/2012/04/19-reverse-order-of-words-in-text.html

public string reverseTheWords(string description)
{
    if(!(string.IsNullOrEmpty(description)) && (description.IndexOf(" ") > 1))
    {
        string[] words= description.Split(' ');
        Array.Reverse(words);
        foreach (string word in words)
        {
            string phrase = string.Join(" ", words);
            Console.WriteLine(phrase);
        }
        return phrase;
    }
    return description;
}

In JAVA

package Test;

public class test2 {

    public static void main(String[] args){

        String str = "my name is fawad X Y Z";

        String strf = "";
        String strfinal="";

        if (str != ""){

        for (int i=0 ; i<=str.length()-1; i++){

            strf += str.charAt(str.length() - (i+1));

        }
        System.out.println(strf);
        }
        else System.out.println("String is Null");

            if (strf != ""){
                String[] temp = strf.split(" ");    

                String temp1 = "";

                System.out.println(temp.length);

                for (int j=0; j<=temp.length-1; j++){

                    temp1 = temp[j];

                    if(temp1.length()>1){

                    for (int k=0; k<=temp1.length()-1; k++){

                        strfinal += temp1.charAt(temp1.length()-(1+k));

                    }
                    strfinal += " ";
                    }
                    else strfinal += temp1 + " ";

                }
                System.out.println(strfinal);

            }
            else System.out.println("String Final is Null");
        }
    }

Output:

Z Y X dawaf si eman ym

Z Y X fawad is name my 

This Question is asked in Paytm interview for Java position. I come up with the following solution.

class ReverseStringWord{
public static void main(String[] args) {
    String s="My name is X Y Z";
    StringBuilder result=new StringBuilder();
    StringBuilder str=new StringBuilder();
    for(int i=0;i<s.length();i++){
        if(s.charAt(i)==' '){
            result.insert(0,str+" ");
            str.setLength(0);
        }
        else{
            str.append(s.charAt(i));
            if(i==s.length()-1){
                result.insert(0,str+" ");
            }
        }
    }
    System.out.println(result);
}}

By doing a rotation of the string you can reverse the order of the words without reversing the order of the letters.

As each word is rotated to the end of the string we reduce the amount of the string to be rotated by the length of the word. We then rotate any spaces to in front of the word we just placed at the end and shorten the rotating part of the string by 1 for each space. If the entire string is rotated with out seeing a space we are done.

Here is am implementation in C+. The l variable contains the length of the buf to rotate, and n counts the number of rotations made.

    #include <stdio.h>
    #include <string.h>
    
    int main(char *argv[], int argc)
    {
      char buf[20] = "My name is X Y Z";
      int l = strlen(buf);
      int n = 1;
    
      while (l >= n) {
        unsigned char c = buf[0];
        for (int i = 1; i < l; i++) {
          buf[i-1] = buf[i];
        }
        buf[l - 1] = c;
        if (buf[0] == ' ' || c == ' ') {
          l -= n;
          n = 1;
        } else {
          n++;
        }
      }
    
      printf("%s\n", buf);
    }

The rotation code was purposely left very simple.

Related