有效地颠倒字符数组中单词(不是字符)的顺序

时间:2008-09-06 12:09:57

标签: algorithm language-agnostic reverse puzzle

给定一个形成单词句子的字符数组,给出一个有效的算法来反转单词(而不是字符)的顺序。

输入和输出示例:

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

它应该是O(N)时间和O(1)空间(split()并且不允许按下/弹出堆栈。)

谜题取自here

21 个答案:

答案 0 :(得分:34)

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

这应该是时间上的O(n)和空间中的O(1)。

编辑:稍微清理一下。

第一遍字符串显然是O(n / 2)= O(n)。第二遍是O(n +所有字的组合长度/ 2)= O(n + n / 2)= O(n),这使得它成为O(n)算法。

答案 1 :(得分:4)

将一个字符串推入堆栈然后将其弹出 - 仍然是O(1)? 基本上,这与使用split()...

相同

O(1)是否意味着就地?如果我们可以只追加字符串和东西,但是使用空间......这个任务变得容易了。

编辑:Thomas Watnedal是对的。以下算法的时间为O(n),空间为O(1):

  1. 就地反向字符串(首次迭代字符串)
  2. 就地反转每个(反向)单词(对字符串另外两次迭代)
    1. 找到第一个单词边界
    2. 在这个单词边界内反转
    3. 重复下一个单词直到完成
  3. 我想我们需要证明第2步实际上只是O(2n)......

答案 2 :(得分: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;
    }
}

答案 3 :(得分:2)

这是我的答案。没有库调用,也没有临时数据结构。

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

答案 4 :(得分:1)

@Daren Thomas

在D(数字火星)中实现你的算法(时间上的O(N),空间中的O(1)):

#!/usr/bin/dmd -run
/**
 * to compile & run:
 * $ dmd -run reverse_words.d
 * to optimize:
 * $ dmd -O -inline -release reverse_words.d
 */
import std.algorithm: reverse;
import std.stdio: writeln;
import std.string: find;

void reverse_words(char[] str) {
  // reverse whole string
  reverse(str);

  // reverse each word
  for (auto i = 0; (i = find(str, " ")) != -1; str = str[i + 1..length])
    reverse(str[0..i]);

  // reverse last word
  reverse(str);
}

void main() {
  char[] str = cast(char[])("this is a string");
  writeln(str);
  reverse_words(str);
  writeln(str);
}

输出:

this is a string
string a is this

答案 5 :(得分:1)

  

这个程序是用C语言&#34; C语言来反转句子。作者:Vasantha kumar&amp;来自Erode的KONGU ENGG COLLEGE的Sundaramoorthy。

注意:句子必须以点(。)结尾  因为没有自动分配NULL字符  在句子结尾*

$wsdl = "http://xxxxx//xxxxx//xxxxx";
$body = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:par="http:///xxxxx.com">
   <soapenv:Header/>
   <soapenv:Body>
      <par:createReservationReq>
         <par:garageID>47</par:garageID>
         <par:orderNumber>orderNumber'.$id.'</par:orderNumber>
         <!--1 or more repetitions:-->
         <par:vehicles>
            <par:barCode>barCode'.$id.'</par:barCode>
            <!--Optional:-->
            <par:licensePlate>licensePlate'.$id.'</par:licensePlate>
            <par:startTime>2015-11-20T22:53:45.547</par:startTime>
            <par:endTime>2015-11-21T22:53:45.547</par:endTime>
            <!--Optional:-->
            <par:vehicleMake>vehicleMake'.$id.'</par:vehicleMake>
            <!--Optional:-->
            <par:vehicleModel>vehicleMode'.$id.'</par:vehicleModel>
            <!--Optional:-->
            <par:vehicleColor>vehicleColor'.$id.'</par:vehicleColor>
         </par:vehicles>
         <!--Optional:-->
         <par:grossPrice>152.6</par:grossPrice>
         <!--Optional:-->
         <par:commFee>162.6</par:commFee>
         <!--Optional:-->
         <par:customerName>customerName'.$id.'</par:customerName>
         <!--Optional:-->
         <par:customerEmail>customerEmail'.$id.'</par:customerEmail>
         <!--Optional:-->
         <par:customerPhone>customerPhone'.$id.'</par:customerPhone>
         <!--Optional:-->
         <par:reentryAllowed>true</par:reentryAllowed>
      </par:createReservationReq>
   </soapenv:Body>
</soapenv:Envelope>';

// initializing cURL with the IPG API URL:
$ch = curl_init($wsdl);

// setting the request type to POST:
curl_setopt($ch, CURLOPT_POST, 1);

// setting the content type:
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: text/xml"));

// setting the authorization method to BASIC:
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);

// filling the request body with your SOAP message:
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);

// telling cURL to verify the server certificate:
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

// telling cURL to return the HTTP response body as operation result
// value when calling curl_exec:
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

// calling cURL and saving the SOAP response message in a variable which
// contains a string like "<SOAP-ENV:Envelope ...>...</SOAP-ENV:Envelope>":

$result = curl_exec($ch);

// loads the XML
$xml = simplexml_load_string($result);

答案 6 :(得分:1)

在Ruby中

  
    

“这是一个字符串”.split.reverse.join(“”)

  

答案 7 :(得分:1)

在伪代码中:

reverse input string
reverse each word (you will need to find word boundaries)

答案 8 :(得分:1)

你会使用所谓的迭代递归函数,它是时间上的O(N),因为它需要N(N是单词的数量)迭代才能完成,而O(1)在空间中,因为每次迭代都保持它函数参数中的自身状态。

(define (reverse sentence-to-reverse)
  (reverse-iter (sentence-to-reverse ""))

(define (reverse-iter(sentence, reverse-sentence)
  (if (= 0 string-length sentence)
    reverse-sentence
    ( reverse-iter( remove-first-word(sentence), add-first-word(sentence, reverse-sentence)))

注意:我已经在计划中写了这个,我是一个完整的新手,所以对缺乏正确的字符串操作道歉。

remove-first-word查找句子的第一个单词边界,然后取出该部分字符(包括空格和标点符号)并删除它并返回新句子

add-first-word查找句子的第一个单词边界,然后取出该部分字符(包括空格和标点符号)并将其添加到反向句子中并返回新的反向句子内容。

答案 9 :(得分:1)

空间中的O(N)和Python中的O(N)时间解决方案:

def reverse_words_nosplit(str_):
  """
  >>> f = reverse_words_nosplit
  >>> f("this is a string")
  'string a is this'
  """
  iend = len(str_)
  s = ""
  while True:
    ispace = str_.rfind(" ", 0, iend)
    if ispace == -1:
      s += str_[:iend]
      break
    s += str_[ispace+1:iend]
    s += " "
    iend = ispace
  return s

答案 10 :(得分:1)

在C :( C99)

#include <stdio.h>
#include <string.h>

void reverseString(char* string, int length)
{
    char swap;
    for (int i = 0; i < length/2; i++)
    {
        swap = string[length - 1 - i];
        string[length - 1 - i] = string[i];
        string[i] = swap;
    }   
}

int main (int argc, const char * argv[]) {
    char teststring[] = "Given an array of characters which form a sentence of words, give an efficient algorithm to reverse the order of the words (not characters) in it.";
    printf("%s\n", teststring);
    int length = strlen(teststring);
    reverseString(teststring, length);
    int i = 0;
    while (i < length)
    {
        int wordlength = strspn(teststring + i, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
        reverseString(teststring + i, wordlength);
        i += wordlength + 1;
    }
    printf("%s\n", teststring);
    return 0;
}

这给出了输出:

  

给出一组字符   形成一个单词的句子,给一个   有效的算法来逆转   中的单词(不是字符)的顺序   它。

     

。在in)字符不是(单词   与算法相反的顺序   有效的给予,句子的话a   形成数组的字符   给定

最多需要4N时间,空间很小。 不幸的是,它没有优雅地处理标点符号或案例。

答案 11 :(得分:0)

using System;

namespace q47407
{
    class MainClass
    {
        public static void Main(string[] args)
        {
            string s = Console.ReadLine();
            string[] r = s.Split(' ');
            for(int i = r.Length-1 ; i >= 0; i--)
                Console.Write(r[i] + " ");
            Console.WriteLine();

        }
    }
}

编辑:我想我应该阅读整个问题......继续。

答案 12 :(得分:0)

C ++解决方案:

#include <string>
#include <iostream>
using namespace std;

string revwords(string in) {
    string rev;
    int wordlen = 0;
    for (int i = in.length(); i >= 0; --i) {
        if (i == 0 || iswspace(in[i-1])) {
            if (wordlen) {
                for (int j = i; wordlen--; )
                    rev.push_back(in[j++]);
                wordlen = 0;
            }
            if (i > 0)
                rev.push_back(in[i-1]);
        }
        else
            ++wordlen;
    }
    return rev;
}

int main() {
    cout << revwords("this is a sentence") << "." << endl;
    cout << revwords("  a sentence   with extra    spaces   ") << "." << endl;
    return 0;
}

答案 13 :(得分:0)

在C#中,就地,O(n)和测试:

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

答案 14 :(得分:0)

在我的时间方面有效:花了不到2分钟写在REBOL中:

reverse_words: func [s [string!]] [form reverse parse s none]

尝试一下:     reverse_words“这是一个字符串”     “字符串a就是这个”

答案 15 :(得分:0)

答案 16 :(得分:0)

这个问题可以用O(n)及时空和O(1)来解决。示例代码如下所示:

    public static string reverseWords(String s)
    {

        char[] stringChar = s.ToCharArray();
        int length = stringChar.Length, tempIndex = 0;

        Swap(stringChar, 0, length - 1);

        for (int i = 0; i < length; i++)
        {
            if (i == length-1)
            {
                Swap(stringChar, tempIndex, i);
                tempIndex = i + 1;
            }
            else if (stringChar[i] == ' ')
            {
                Swap(stringChar, tempIndex, i-1);
                tempIndex = i + 1;
            }
        }

        return new String(stringChar);
    }

    private static void Swap(char[] p, int startIndex, int endIndex)
    {
        while (startIndex < endIndex)
        {
            p[startIndex] ^= p[endIndex];
            p[endIndex] ^= p[startIndex];
            p[startIndex] ^= p[endIndex];
            startIndex++;
            endIndex--;
        }
    }

答案 17 :(得分:0)

一个班轮:

l="Is this as expected ??"
" ".join(each[::-1] for each in l[::-1].split())

输出:

'?? expected as this Is'

答案 18 :(得分:0)

  

算法:   1)。反转字符串的每个单词。   2)。反向结果字符串。

public class Solution {
public String reverseWords(String p) {
   String reg=" ";
  if(p==null||p.length()==0||p.equals(""))
{
    return "";
}
String[] a=p.split("\\s+");
StringBuilder res=new StringBuilder();;
for(int i=0;i<a.length;i++)
{

    String temp=doReverseString(a[i]);
    res.append(temp);
    res.append(" ");
}
String resultant=doReverseString(res.toString());
System.out.println(res);
return resultant.toString().replaceAll("^\\s+|\\s+$", ""); 
}


public String doReverseString(String s)`{`


char str[]=s.toCharArray();
int start=0,end=s.length()-1;
while(start<end)
{
char temp=str[start];
str[start]=str[end];
str[end]=temp;
start++;
end--;
}
String a=new String(str);
return a;

}

public static void main(String[] args)
{
Solution r=new Solution();
String main=r.reverseWords("kya hua");
//System.out.println(re);
System.out.println(main);
}
}

答案 19 :(得分:0)

解决这个问题的算法是基于两个步骤的过程,第一步将反转字符串的单个字,然后在第二步,反转整个字符串。算法的实现将花费O(n)时间和O(1)空间复杂度。

      #include <stdio.h>
      #include <string.h>

      void reverseStr(char* s, int start, int end);

      int main()
      {
              char s[] = "This is test string";

              int start = 0;
              int end = 0;
              int i = 0;

              while (1) {

              if (s[i] == ' ' || s[i] == '\0')
              {
                    reverseStr(s, start, end-1);
                    start = i + 1;
                    end = start;
              }
              else{
                    end++;
              }

              if(s[i] == '\0'){
                   break;
              }
              i++;
      }

      reverseStr(s, 0, strlen(s)-1);
      printf("\n\noutput= %s\n\n", s);

      return 0;
  }

  void reverseStr(char* s, int start, int end)
  {
     char temp;
     int j = end;
     int i = start;

     for (i = start; i < j ; i++, j--) {
          temp = s[i];
          s[i] = s[j];
          s[j] = temp;
     }
 }

答案 20 :(得分:0)

将每个单词推入堆栈。弹出堆栈中的所有单词。