紧凑,可读,高效的C ++算法,用于反转字符串IN-PLACE的单词

时间:2015-04-20 04:10:51

标签: c++ algorithm

所以我试图为提示

提供一个好的C ++解决方案
  

“反转字符串中的单词(单词分隔一个或多个   空格)。现在就地进行。到目前为止最流行的字符串问题!“

我现在拥有的是一种怪物:

void reverse_words ( std::string & S )
{
/* 
    Programming interview question: "Reverse words in a string (words are separated by one or more spaces). Now do it in-place. By far the most popular string question!"
    http://maxnoy.com/interviews.html 
*/
    if (S.empty()) return;
    std::string::iterator ita = S.begin() , itb = S.end() - 1;
    while (ita != itb) 
    {
      if (*ita != ' ')
      {
         std::string sa; // string to hold the current leftmost sequence of non-whitespace characters
         std::string::iterator tempa = ita; // iterator to the beginning of sa within S
         while (ita != ' ' && ita != itb) sa.push_back(*ita++); // fill sa
         while (*itb == ' ' && itb != ita) --itb; // move itb back to the first non-whitespace character preceding it
         std::string sb; // string to hold the current rightmost sequence of non-whitespace characters
         std::string::iterator tempb = itb; // iterator to the end of sb within S
         while (*itb != ' ' && itb != ita) sb.push_back(*itb--); // fill sb
         S.replace(tempa, ita-tempa, sb); // replace the current leftmost string with the current rightmost one
         S.replace(tempb, itb-tempb, sa); // and vice-versa
       }
      else
      {
         ++ita; 
      }
    }   
}

我认为我有正确的想法(找到第一个字符串,用最后一个字符串交换,在第一个字符串之后找到下一个字符串,用最后一个字符串交换,等等),但是我需要一些更好的工具来让这件事成真。如何利用标准库来解决这个问题?

2 个答案:

答案 0 :(得分:3)

如果您使用以下方法,这非常简单:

  1. 反转整个字符串。
  2. 单独翻转每个单词。
  3. 这个算法已经是O(n),你只需要遍历整个字符串一次,然后再找到一个反向的每个单词。

    现在,为了提高效率,请查看算法以反转序列,该序列从正面和背面读取一个序列,并将每个序列存储在另一个位置。现在,每当你存储一个空格时,你只是终止了一个单词,所以现在就反转这个单词。更有效的原因是包含该字的缓存在CPU上仍然很热。这里的困难是在角落里做到这一点。你必须考虑字符串两端的中间字,多个连续的空格和空格。

答案 1 :(得分:0)

我猜是这样的。简单,高效,清晰。请注意,std::basic_string::find...npos会返回pos >= str.size()

void ReverseWords(std::string& msg) {
    std::string::size_type pos_a = 0, pos_b = -1;
    while ((pos_a = msg.find_first_not_of(' ', pos_b + 1)) != msg.npos) {
        pos_b = std::min(msg.find(' ', pos_a + 1), msg.size());
        std::reverse(msg.begin() + pos_a, msg.begin() + pos_b);
    }
    std::reverse(msg.begin(), msg.end());
}