68 votes

Inverser l'ordre des mots dans une chaîne de caractères

J'ai ceci string s1 = "My name is X Y Z" et je veux inverser l'ordre des mots pour que s1 = "Z Y X is name My" .

Je peux le faire en utilisant un tableau supplémentaire. J'ai bien réfléchi mais est-il possible de le faire en place (sans utiliser de structures de données supplémentaires) et avec une complexité temporelle de O(n) ?

0 votes

Qu'entendez-vous par tableau supplémentaire ? En plus de celui que vous utiliseriez pour stocker les "tokens" (c'est-à-dire les mots), ou en plus de la chaîne de caractères que vous avez donnée en exemple ?

3 votes

21 votes

string.split(' ').reverse().join(' ')

128voto

Bill the Lizard Points 147311

Inversez la chaîne entière, puis inversez les lettres de chaque mot.

Après le premier passage, la chaîne sera

s1 = "Z Y X si eman yM"

et après le deuxième passage, ce sera

s1 = "Z Y X is name My"

2 votes

"nom", par exemple, n'est pas inversé dans son exemple.

15 votes

C'est pour ça qu'on fait une deuxième passe pour inverser les lettres de chaque mot.

1 votes

Cela fonctionne, mais l'ordre de complexité n'est-il pas supérieur à O(n) alors ? !

33voto

Demi Points 3547

inverser la chaîne et ensuite, dans un deuxième temps, inverser chaque mot...

en c#, complètement in-place sans tableaux supplémentaires :

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

1 votes

Pensez-vous que c'est une opération O(n) ? Lorsque nous appelons ReverseString à l'intérieur de cette boucle for, je pense que cela ne se produit pas en temps O(n).

3 votes

@Pritam : ReverseString n'est pas exécuté dans la boucle for à chaque fois. Il y a une passe inverse complète sur la chaîne (première passe), puis la boucle for trouve les espaces qui délimitent les frontières des mots (une autre passe). Le ReverseString appelé à l'intérieur (et, ce qui est important, pas à chaque index) est O(m), où m est la longueur du mot. Elle est appelée pour chaque mot. La somme de toutes les opérations de longueur de mot O(m) est équivalente à O(n). Ainsi, cet algorithme est dans le pire des cas 3 * O(n), ce qui est toujours O(n). Si ReverseString était appelé à chaque index, je pense que vous auriez raison...

0 votes

Qu'en est-il des espaces consécutifs dans les mots ?

16voto

Not exactly in place, but anyway: Python:

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

13voto

Wrameerez Points 91

Dans Smalltalk :

'These pretzels are making me thirsty' subStrings reduce: [:a :b| b, ' ', a]

Je sais que personne ne s'intéresse à Smalltalk, mais c'est si beau pour moi.

4voto

baumgart Points 165

Vous ne pouvez pas faire l'inversion sans au moins une structure de données supplémentaire. Je pense que la plus petite structure serait un seul caractère comme tampon pendant que vous échangez les lettres. On peut toujours considérer que c'est "en place", mais ce n'est pas complètement "sans structure de données supplémentaire".

Vous trouverez ci-dessous le code mettant en œuvre ce que Bill le Lézard décrit :

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

5 votes

Vous pouvez le faire sans caractère supplémentaire si vous utilisez une astuce binaire ou arithmétique. Par exemple : a ^= b ; b ^= a ; a ^= b ; échangera a et b.

0 votes

Vous auriez pu stocker len = strlen(words) . Utilisation de strlen(words) autant de fois prendra plus de temps.

1 votes

Peut-être un peu tard, mais ça ne devrait pas être le cas. for(int j = wordstart ; j <= (wordend + wordstart) / 2 ; ++j) dans la dernière boucle for au lieu de moins ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X