Обратный порядок слов в строке - PullRequest
68 голосов
/ 17 июня 2009

У меня есть string s1 = "My name is X Y Z", и я хочу изменить порядок слов так, чтобы s1 = "Z Y X is name My".

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

Ответы [ 47 ]

1 голос
/ 28 января 2016

Печать слов в обратном порядке заданного оператора с использованием C #:

    void ReverseWords(string str)
    {
        int j = 0;
        for (int i = (str.Length - 1); i >= 0; i--)
        {
            if (str[i] == ' ' || i == 0)
            {
                j = i == 0 ? i : i + 1;

                while (j < str.Length && str[j] != ' ')
                    Console.Write(str[j++]);
                Console.Write(' ');
            }
        }
    }
1 голос
/ 10 ноября 2011

Это не идеально, но у меня работает прямо сейчас. Я не знаю, имеет ли он O (n) время выполнения между прочим (все еще изучает его ^^), но он использует один дополнительный массив для выполнения задачи.

Вероятно, это не лучший ответ на вашу проблему, потому что я использую строку dest для сохранения обратной версии вместо замены каждого слова в исходной строке. Проблема в том, что я использую локальную переменную стека с именем buf, чтобы скопировать все слова в, и я не могу скопировать, но в исходную строку, поскольку это приведет к падению, если исходная строка имеет тип const char *.

Но это была моя первая попытка написать s.th. как это :) Хорошо достаточно Blablub. вот код:

#include <iostream>
using namespace std;

void reverse(char *des, char * const s);
int main (int argc, const char * argv[])
{    
    char* s = (char*)"reservered. rights All Saints. The 2011 (c) Copyright 11/10/11 on Pfundstein Markus by Created";
    char *x = (char*)"Dogfish! White-spotted Shark, Bullhead";

    printf("Before: |%s|\n", x);
    printf("Before: |%s|\n", s);

    char *d = (char*)malloc((strlen(s)+1)*sizeof(char));  
    char *i = (char*)malloc((strlen(x)+1)*sizeof(char));

    reverse(d,s);
    reverse(i,x);

    printf("After: |%s|\n", i);
    printf("After: |%s|\n", d);

    free (i);
    free (d);

    return 0;
}

void reverse(char *dest, char *const s) {
    // create a temporary pointer
    if (strlen(s)==0) return;
    unsigned long offset = strlen(s)+1;

    char *buf = (char*)malloc((offset)*sizeof(char));
    memset(buf, 0, offset);

    char *p;
    // iterate from end to begin and count how much words we have
    for (unsigned long i = offset; i != 0; i--) {
        p = s+i;
        // if we discover a whitespace we know that we have a whole word
        if (*p == ' ' || *p == '\0') {
            // we increment the counter
            if (*p != '\0') {
                // we write the word into the buffer
                ++p;
                int d = (int)(strlen(p)-strlen(buf));
                strncat(buf, p, d);
                strcat(buf, " ");
            }
        }
    }

    // copy the last word
    p -= 1;
    int d = (int)(strlen(p)-strlen(buf));
    strncat(buf, p, d);
    strcat(buf, "\0");

    // copy stuff to destination string
    for (int i = 0; i < offset; ++i) {
        *(dest+i)=*(buf+i);
    }

    free(buf);
}
1 голос
/ 26 сентября 2015

В Python, если вы не можете использовать [:: - 1] или reversed (), вот простой способ:

def reverse(text):

  r_text = text.split(" ")
  res = []
  for word in range(len(r_text) - 1, -1, -1): 
    res.append(r_text[word])

  return " ".join(res)

print (reverse("Hello World"))

>> World Hello
[Finished in 0.1s]
1 голос
/ 13 августа 2012

Эта быстрая программа работает ... но не проверяет угловые случаи.

#include <stdio.h>
#include <stdlib.h>
struct node
{
    char word[50];
    struct node *next;
};
struct stack
{
    struct node *top;
};
void print (struct stack *stk);
void func (struct stack **stk, char *str);
main()
{
    struct stack *stk = NULL;
    char string[500] = "the sun is yellow and the sky is blue";
    printf("\n%s\n", string);
    func (&stk, string);
    print (stk);
}
void func (struct stack **stk, char *str)
{
    char *p1 = str;
    struct node *new = NULL, *list = NULL;
    int i, j;
    if (*stk == NULL)
    {
        *stk = (struct stack*)malloc(sizeof(struct stack));
        if (*stk == NULL)
            printf("\n####### stack is not allocated #####\n");
        (*stk)->top = NULL;
    }
    i = 0;
    while (*(p1+i) != '\0')
    {
        if (*(p1+i) != ' ')
        {
            new = (struct node*)malloc(sizeof(struct node));
            if (new == NULL)
                printf("\n####### new is not allocated #####\n");
            j = 0;
            while (*(p1+i) != ' ' && *(p1+i) != '\0')
            {
                new->word[j] = *(p1 + i);
                i++;
                j++;
            }
            new->word[j++] = ' ';
            new->word[j] = '\0';
            new->next = (*stk)->top;
            (*stk)->top = new;
        }
        i++;
   }
}
void print (struct stack *stk)
{
    struct node *tmp = stk->top;
    int i;
    while (tmp != NULL)
    {
        i = 0;
        while (tmp->word[i] != '\0')
        {
            printf ("%c" , tmp->word[i]);
            i++;
        }
        tmp = tmp->next;
    }
    printf("\n");
}
1 голос
/ 27 января 2012

Мы можем вставить строку в стек, и когда мы извлечем слова, они будут в обратном порядке.

void ReverseWords(char Arr[])
{
    std::stack<std::string> s;
    char *str;
    int length = strlen(Arr);
    str = new char[length+1];
    std::string ReversedArr;
    str = strtok(Arr," ");
    while(str!= NULL)
    {
        s.push(str);
        str = strtok(NULL," ");
    }
    while(!s.empty())
    {
        ReversedArr = s.top();
        cout << " " << ReversedArr;
        s.pop();
    }
}
1 голос
/ 07 марта 2014

Моя версия использования стека:

public class Solution {
    public String reverseWords(String s) {
        StringBuilder sb = new StringBuilder();
        String ns= s.trim();
        Stack<Character> reverse = new Stack<Character>();
        boolean hadspace=false;

        //first pass
        for (int i=0; i< ns.length();i++){
            char c = ns.charAt(i);
            if (c==' '){
                if (!hadspace){
                    reverse.push(c);
                    hadspace=true;
                }
            }else{
                hadspace=false;
                reverse.push(c);
            }
        }
        Stack<Character> t = new Stack<Character>();
        while (!reverse.empty()){
            char temp =reverse.pop();
            if(temp==' '){
                //get the stack content out append to StringBuilder
                while (!t.empty()){
                    char c =t.pop();
                    sb.append(c);
                }
                sb.append(' ');
            }else{
                //push to stack
                t.push(temp);
            }
        }
        while (!t.empty()){
            char c =t.pop();
            sb.append(c);
        }
        return sb.toString();
    }
}
1 голос
/ 17 декабря 2014

Сохранять каждое слово в виде строки в массиве, затем печатать с конца

public void rev2() {
    String str = "my name is ABCD";
    String A[] = str.split(" ");

    for (int i = A.length - 1; i >= 0; i--) {
        if (i != 0) {
            System.out.print(A[i] + " ");
        } else {
            System.out.print(A[i]);
        }
    }

}
1 голос
/ 06 ноября 2013

В большинстве этих ответов не учитываются начальные и / или конечные пробелы во входной строке. Рассмотрим случай str=" Hello world" ... Простой алгоритм перестановки всей строки и обращения отдельных слов приводит к переворачиванию разделителей, в результате чего получается f(str) == "world Hello ".

ОП сказала «Я хочу изменить порядок слов» и не упомянула, что начальные и конечные пробелы также должны быть перевернуты! Итак, хотя ответов уже много, я приведу [надеюсь] более правильный ответ в 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);
}
1 голос
/ 08 ноября 2018

Вот реализация Java:

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;
    }
}
0 голосов
/ 18 июня 2009

Как насчет ...

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

Я полагаю, что это не in-line.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...